// ==UserScript==
// @name              网盘直链下载助手
// @namespace         https://greasyfork.org/zh-CN/users/76501-eroslp
// @version           6.2.7
// @author            eroslp
// @description       👆👆👆👆👆👆👆 (自动显示暗号)- 支持批量获取 ✅百度网盘 ✅阿里云盘 ✅天翼云盘 ✅迅雷云盘 ✅夸克网盘 ✅移动云盘 六大网盘的直链下载地址，配合 IDM，Xdown，Aria2，Curl，比特彗星等工具高效🚀🚀🚀下载，完美适配 Chrome，Edge，FireFox，360，QQ，搜狗，百分，遨游，星愿，Opera，猎豹，Vivaldi，Yandex，Kiwi 等 18 种浏览器。可在无法安装客户端的环境下使用，助手免费开源。😎
// @license           AGPL-3.0-or-later
// @homepage          https://greasyfork.org/zh-CN/users/76501-eroslp
// @supportURL        https://greasyfork.org/zh-CN/users/76501-eroslp
// @match             *://pan.baidu.com/disk/home*
// @match             *://yun.baidu.com/disk/home*
// @match             *://pan.baidu.com/disk/main*
// @match             *://yun.baidu.com/disk/main*
// @match             *://pan.baidu.com/s/*
// @match             *://yun.baidu.com/s/*
// @match             *://pan.baidu.com/share/*
// @match             *://yun.baidu.com/share/*
// @match             *://openapi.baidu.com/*
// @match             *://www.aliyundrive.com/s/*
// @match             *://www.aliyundrive.com/drive*
// @match             *://www.alipan.com/s/*
// @match             *://www.alipan.com/drive*
// @match             *://cloud.189.cn/web/*
// @match             *://pan.xunlei.com/*
// @match             *://pan.quark.cn/*
// @match             *://yun.139.com/*
// @match             *://caiyun.139.com/*
// @require           https://unpkg.com/jquery@3.7.0/dist/jquery.min.js
// @require           https://unpkg.com/sweetalert2@10.16.6/dist/sweetalert2.all.min.js
// @require           https://unpkg.com/js-md5@0.7.3/build/md5.min.js
// @connect           baidu.com
// @connect           baidupcs.com
// @connect           aliyundrive.com
// @connect           alipan.com
// @connect           189.cn
// @connect           xunlei.com
// @connect           quark.cn
// @connect           youxiaohou.com
// @connect           yun.139.com
// @connect           caiyun.139.com
// @connect           localhost
// @connect           *
// @run-at            document-idle
// @grant             unsafeWindow
// @grant             GM_xmlhttpRequest
// @grant             GM_setClipboard
// @grant             GM_setValue
// @grant             GM_getValue
// @grant             GM_deleteValue
// @grant             GM_openInTab
// @grant             GM_info
// @grant             GM_registerMenuCommand
// @grant             GM_cookie
// @grant             window.close
// @icon              
// @downloadURL https://update.greasyfork.org/scripts/512125/%E7%BD%91%E7%9B%98%E7%9B%B4%E9%93%BE%E4%B8%8B%E8%BD%BD%E5%8A%A9%E6%89%8B%20%EF%BC%88%E8%87%AA%E5%8A%A8%E6%98%BE%E7%A4%BA%E6%9A%97%E5%8F%B7%EF%BC%89.user.js
// @updateURL https://update.greasyfork.org/scripts/512125/%E7%BD%91%E7%9B%98%E7%9B%B4%E9%93%BE%E4%B8%8B%E8%BD%BD%E5%8A%A9%E6%89%8B%20%EF%BC%88%E8%87%AA%E5%8A%A8%E6%98%BE%E7%A4%BA%E6%9A%97%E5%8F%B7%EF%BC%89.meta.js
// ==/UserScript==

(function () {
  "use strict";
  let pt = "",
    selectList = [],
    params = {},
    mode = "",
    width = 800,
    pan = {},
    color = "",
    doc = $(document),
    progress = {},
    request = {},
    ins = {},
    idm = {};
  const scriptInfo = GM_info.script;
  const version = scriptInfo.version;
  const author = scriptInfo.author;
  const name = scriptInfo.name;
  const manageHandler = GM_info.scriptHandler;
  const manageVersion = GM_info.version;
  const customClass = {
    popup: "pl-popup",
    header: "pl-header",
    title: "pl-title",
    closeButton: "pl-close",
    content: "pl-content",
    input: "pl-input",
    footer: "pl-footer",
  };

  const terminalType = {
    wc: "Windows CMD",
    wp: "Windows PowerShell",
    lt: "Linux 终端",
    ls: "Linux Shell",
    mt: "MacOS 终端",
  };

  let toast = Swal.mixin({
    toast: true,
    position: "top",
    showConfirmButton: false,
    timer: 3500,
    timerProgressBar: false,
    didOpen: (toast) => {
      toast.addEventListener("mouseenter", Swal.stopTimer);
      toast.addEventListener("mouseleave", Swal.resumeTimer);
    },
  });

  const message = {
    success: (text) => {
      toast.fire({ title: text, icon: "success" });
    },
    error: (text) => {
      toast.fire({ title: text, icon: "error" });
    },
    warning: (text) => {
      toast.fire({ title: text, icon: "warning" });
    },
    info: (text) => {
      toast.fire({ title: text, icon: "info" });
    },
    question: (text) => {
      toast.fire({ title: text, icon: "question" });
    },
  };

  let base = {
    getCookie(name) {
      let cname = name + "=";
      let ca = document.cookie.split(";");
      for (let i = 0; i < ca.length; i++) {
        let c = ca[i].trim();
        if (c.indexOf(cname) == 0) return c.substring(cname.length, c.length);
      }
      return "";
    },

    isType(obj) {
      return Object.prototype.toString
        .call(obj)
        .replace(/^\[object (.+)\]$/, "$1")
        .toLowerCase();
    },

    getValue(name) {
      return GM_getValue(name);
    },

    setValue(name, value) {
      GM_setValue(name, value);
    },

    deleteValue(name) {
      GM_deleteValue(name);
    },

    getStorage(key) {
      try {
        return JSON.parse(localStorage.getItem(key));
      } catch (e) {
        return localStorage.getItem(key);
      }
    },

    setStorage(key, value) {
      if (this.isType(value) === "object" || this.isType(value) === "array") {
        return localStorage.setItem(key, JSON.stringify(value));
      }
      return localStorage.setItem(key, value);
    },

    setClipboard(text) {
      GM_setClipboard(text, "text");
    },

    e(str) {
      return btoa(unescape(encodeURIComponent(str)));
    },

    d(str) {
      return decodeURIComponent(escape(atob(str)));
    },

    getExtension(name) {
      const reg = /(?!\.)\w+$/;
      if (reg.test(name)) {
        let match = name.match(reg);
        return match[0].toUpperCase();
      }
      return "";
    },

    sizeFormat(value) {
      if (value === +value) {
        let unit = ["B", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"];
        let index = Math.floor(Math.log(value) / Math.log(1024));
        let size = value / Math.pow(1024, index);
        size = size.toFixed(1);
        return size + unit[index];
      }
      return "";
    },

    sortByName(arr) {
      const handle = () => {
        return (a, b) => {
          const p1 = a.filename ? a.filename : a.server_filename;
          const p2 = b.filename ? b.filename : b.server_filename;
          return p1.localeCompare(p2, "zh-CN");
        };
      };
      arr.sort(handle());
    },

    fixFilename(name) {
      return name.replace(/[!?&|`"'*\/:<>\\]/g, "_");
    },

    blobDownload(blob, filename) {
      if (blob instanceof Blob) {
        const url = URL.createObjectURL(blob);
        const a = document.createElement("a");
        a.href = url;
        a.download = filename;
        a.click();
        URL.revokeObjectURL(url);
      }
    },
    post(url, data, headers, type) {
      if (this.isType(data) === "object") {
        data = JSON.stringify(data);
      }
      return new Promise((resolve, reject) => {
        GM_xmlhttpRequest({
          method: "POST",
          url,
          headers,
          data,
          responseType: type || "json",
          onload: (res) => {
            type === "blob" ? resolve(res) : resolve(res.response || res.responseText);
          },
          onerror: (err) => {
            reject(err);
          },
        });
      });
    },

    get(url, headers, type, extra) {
      return new Promise((resolve, reject) => {
        let requestObj = GM_xmlhttpRequest({
          method: "GET",
          url,
          headers,
          responseType: type || "json",
          onload: (res) => {
            if (res.status === 204) {
              requestObj.abort();
              idm[extra.index] = true;
            }
            if (type === "blob") {
              res.status === 200 && base.blobDownload(res.response, extra.filename);
              resolve(res);
            } else {
              resolve(res.response || res.responseText);
            }
          },
          onprogress: (res) => {
            if (extra && extra.filename && extra.index) {
              res.total > 0 ? (progress[extra.index] = ((res.loaded * 100) / res.total).toFixed(2)) : (progress[extra.index] = 0.0);
            }
          },
          onloadstart() {
            extra && extra.filename && extra.index && (request[extra.index] = requestObj);
          },
          onerror: (err) => {
            reject(err);
          },
        });
      });
    },

    getFinalUrl(url, headers) {
      return new Promise((resolve, reject) => {
        let requestObj = GM_xmlhttpRequest({
          method: "GET",
          url,
          headers,
          onload: (res) => {
            resolve(res.finalUrl);
          },
          onerror: (err) => {
            reject(err);
          },
        });
      });
    },

    stringify(obj) {
      let str = "";
      for (var key in obj) {
        if (obj.hasOwnProperty(key)) {
          var value = obj[key];
          if (Array.isArray(value)) {
            for (var i = 0; i < value.length; i++) {
              str += encodeURIComponent(key) + "=" + encodeURIComponent(value[i]) + "&";
            }
          } else {
            str += encodeURIComponent(key) + "=" + encodeURIComponent(value) + "&";
          }
        }
      }
      return str.slice(0, -1); // 去掉末尾的 "&"
    },

    addStyle(id, tag, css) {
      tag = tag || "style";
      let doc = document,
        styleDom = doc.getElementById(id);
      if (styleDom) return;
      let style = doc.createElement(tag);
      style.rel = "stylesheet";
      style.id = id;
      tag === "style" ? (style.innerHTML = css) : (style.href = css);
      doc.getElementsByTagName("head")[0].appendChild(style);
    },

    sleep(time) {
      return new Promise((resolve) => setTimeout(resolve, time));
    },

    getMajorVersion(version) {
      const [major] = (version || "").split(".");
      return /^\d+$/.test(major) ? major : null;
    },

    findReact(dom, traverseUp = 0) {
      const key = Object.keys(dom).find((key) => {
        return key.startsWith("__reactFiber$") || key.startsWith("__reactInternalInstance$");
      });
      const domFiber = dom[key];
      if (domFiber == null) return null;

      if (domFiber._currentElement) {
        let compFiber = domFiber._currentElement._owner;
        for (let i = 0; i < traverseUp; i++) {
          compFiber = compFiber._currentElement._owner;
        }
        return compFiber._instance;
      }

      const GetCompFiber = (fiber) => {
        let parentFiber = fiber.return;
        while (typeof parentFiber.type == "string") {
          parentFiber = parentFiber.return;
        }
        return parentFiber;
      };
      let compFiber = GetCompFiber(domFiber);
      for (let i = 0; i < traverseUp; i++) {
        compFiber = GetCompFiber(compFiber);
      }
      return compFiber.stateNode || compFiber;
    },

    initDefaultConfig() {
      let value = [
        {
          name: "setting_rpc_domain",
          value: "http://localhost",
        },
        {
          name: "setting_rpc_port",
          value: "16800",
        },
        {
          name: "setting_rpc_path",
          value: "/jsonrpc",
        },
        {
          name: "setting_rpc_token",
          value: "",
        },
        {
          name: "setting_rpc_dir",
          value: "D:",
        },
        {
          name: "setting_terminal_type",
          value: "wc",
        },
        {
          name: "setting_theme_color",
          value: "#09AAFF",
        },
        {
          name: "setting_init_code",
          value: "",
        },
        {
          name: "license",
          value: "",
        },
      ];

      value.forEach((v) => {
        base.getValue(v.name) === undefined && base.setValue(v.name, v.value);
      });
    },

    showSetting() {
      let dom = "",
        btn = "",
        colorList = ["#09AAFF", "#cc3235", "#526efa", "#518c17", "#ed944b", "#f969a5", "#bca280"];
      dom += `<label class="pl-setting-label"><div class="pl-label">RPC主机</div><input type="text"  placeholder="主机地址，需带上http(s)://" class="pl-input listener-domain" value="${base.getValue("setting_rpc_domain")}"></label>`;
      dom += `<label class="pl-setting-label"><div class="pl-label">RPC端口</div><input type="text" placeholder="端口号，例如：Motrix为16800" class="pl-input listener-port" value="${base.getValue("setting_rpc_port")}"></label>`;
      dom += `<label class="pl-setting-label"><div class="pl-label">RPC路径</div><input type="text" placeholder="路径，默认为/jsonrpc" class="pl-input listener-path" value="${base.getValue("setting_rpc_path")}"></label>`;
      dom += `<label class="pl-setting-label"><div class="pl-label">RPC密钥</div><input type="text" placeholder="无密钥无需填写" class="pl-input listener-token" value="${base.getValue("setting_rpc_token")}"></label>`;
      dom += `<label class="pl-setting-label"><div class="pl-label">保存路径</div><input type="text" placeholder="文件下载后保存路径，例如：D:" class="pl-input listener-dir" value="${base.getValue("setting_rpc_dir")}"></label>`;

      colorList.forEach((v) => {
        btn += `<div data-color="${v}" style="background: ${v};border: 1px solid ${v}" class="pl-color-box listener-color ${v === base.getValue("setting_theme_color") ? "checked" : ""}"></div>`;
      });
      dom += `<label class="pl-setting-label"><div class="pl-label">终端类型</div><select class="pl-input listener-terminal">`;
      Object.keys(terminalType).forEach((k) => {
        dom += `<option value="${k}" ${base.getValue("setting_terminal_type") === k ? "selected" : ""}>${terminalType[k]}</option>`;
      });
      dom += `</select></label>`;
      dom += `<label class="pl-setting-label"><div class="pl-label">主题颜色</div> <div class="pl-color">${btn}<div></label>`;
      dom = "<div>" + dom + "</div>";

      Swal.fire({
        title: "助手配置",
        html: dom,
        icon: "info",
        showCloseButton: true,
        showConfirmButton: false,
        footer: pan.footer,
      }).then(() => {
        message.success("设置成功！");
        history.go(0);
      });

      doc.on("click", ".listener-color", async (e) => {
        base.setValue("setting_theme_color", e.target.dataset.color);
        message.success("设置成功！");
        history.go(0);
      });
      doc.on("input", ".listener-domain", async (e) => {
        base.setValue("setting_rpc_domain", e.target.value);
      });
      doc.on("input", ".listener-port", async (e) => {
        base.setValue("setting_rpc_port", e.target.value);
      });
      doc.on("input", ".listener-path", async (e) => {
        base.setValue("setting_rpc_path", e.target.value);
      });
      doc.on("input", ".listener-token", async (e) => {
        base.setValue("setting_rpc_token", e.target.value);
      });
      doc.on("input", ".listener-dir", async (e) => {
        base.setValue("setting_rpc_dir", e.target.value);
      });
      doc.on("change", ".listener-terminal", async (e) => {
        base.setValue("setting_terminal_type", e.target.value);
      });
    },

    registerMenuCommand() {
      GM_registerMenuCommand("⚙️ 设置", () => {
        this.showSetting();
      });
    },

    createTip() {
      $("body").append('<div class="pl-tooltip"></div>');

      doc.on("mouseenter mouseleave", ".listener-tip", (e) => {
        if (e.type === "mouseenter") {
          let filename = e.currentTarget.innerText;
          let size = e.currentTarget.dataset.size;
          let tip = `${filename}<span style="margin-left: 10px;color: #f56c6c;">${size}</span>`;
          $(e.currentTarget).css({ opacity: "0.5" });
          $(".pl-tooltip")
            .html(tip)
            .css({
              left: e.pageX + 10 + "px",
              top: e.pageY - e.currentTarget.offsetTop > 14 ? e.pageY + "px" : e.pageY + 20 + "px",
            })
            .show();
        } else {
          $(e.currentTarget).css({ opacity: "1" });
          $(".pl-tooltip").hide(0);
        }
      });
    },

    createLoading() {
      return $('<div class="pl-loading"><div class="pl-loading-box"><div><div></div><div></div></div></div></div>');
    },

    createDownloadIframe() {
      let $div = $('<div style="padding:0;margin:0;display:block"></div>');
      let $iframe = $('<iframe src="javascript:;" id="downloadIframe" style="display:none"></iframe>');
      $div.append($iframe);
      $("body").append($div);
    },

    getMirrorList(link, mirror, thread = 2) {
      let host = new URL(link).host;
      let mirrors = [];
      for (let i = 0; i < mirror.length; i++) {
        for (let j = 0; j < thread; j++) {
          let item = link.replace(host, mirror[i]) + "&".repeat(j);
          mirrors.push(item);
        }
      }
      return mirrors.join("\n");
    },

    listenElement(element, callback) {
      const checkInterval = 500; // 检查元素的间隔时间（毫秒）
      let wasElementFound = false; // 用于跟踪元素是否之前已经找到

      function checkElement() {
        if (document.querySelector(element)) {
          wasElementFound = true;
          callback();
        } else if (wasElementFound) {
          wasElementFound = false; // 元素消失后重置标志
        }

        setTimeout(checkElement, checkInterval);
      }

      checkElement();
    },

    addPanLinkerStyle() {
      color = base.getValue("setting_theme_color");
      let css = `
          body::-webkit-scrollbar { display: none }
          ::-webkit-scrollbar { width: 6px; height: 10px }
          ::-webkit-scrollbar-track { border-radius: 0; background: none }
          ::-webkit-scrollbar-thumb { background-color: rgba(85,85,85,.4) }
          ::-webkit-scrollbar-thumb,::-webkit-scrollbar-thumb:hover { border-radius: 5px; -webkit-box-shadow: inset 0 0 6px rgba(0,0,0,.2) }
          ::-webkit-scrollbar-thumb:hover { background-color: rgba(85,85,85,.3) }
          .swal2-popup { font-size: 16px !important; }
          .pl-popup { font-size: 12px !important; }
          .pl-popup a { color: ${color} !important; }
          .pl-header { padding: 0!important;align-items: flex-start!important; border-bottom: 1px solid #eee!important; margin: 0 0 10px!important; padding: 0 0 5px!important; }
          .pl-title { font-size: 16px!important; line-height: 1!important;white-space: nowrap!important; text-overflow: ellipsis!important;}
          .pl-content { padding: 0 !important; font-size: 12px!important; }
          .pl-main { max-height: 400px;overflow-y:scroll; }
          .pl-footer {font-size: 12px!important;justify-content: flex-start!important; margin: 10px 0 0!important; padding: 5px 0 0!important; color: #f56c6c!important; }
          .pl-item { display: flex; align-items: center; line-height: 22px; }
          .pl-item-name { flex: 0 0 150px; text-align: left;margin-right: 10px; overflow: hidden; white-space: nowrap; text-overflow: ellipsis; cursor:default; }
          .pl-item-link { flex: 1; overflow: hidden; text-align: left; white-space: nowrap; text-overflow: ellipsis;cursor:pointer }
          .pl-item-btn { background: ${color}; padding: 4px 5px; border-radius: 3px; line-height: 1; cursor: pointer; color: #fff; }
          .pl-item-tip { display: flex; justify-content: space-between;flex: 1; }
          .pl-back { width: 70px; background: #ddd; border-radius: 3px; cursor:pointer; margin:1px 0; }
          .pl-ext { display: inline-block; width: 44px; background: #999; color: #fff; height: 16px; line-height: 16px; font-size: 12px; border-radius: 3px;}
          .pl-retry {padding: 3px 10px; background: #cc3235; color: #fff; border-radius: 3px; cursor: pointer;}
          .pl-browserdownload { padding: 3px 10px; background: ${color}; color: #fff; border-radius: 3px; cursor: pointer;}
          .pl-item-progress { display:flex;flex: 1;align-items:center}
          .pl-progress { display: inline-block;vertical-align: middle;width: 100%; box-sizing: border-box;line-height: 1;position: relative;height:15px; flex: 1}
          .pl-progress-outer { height: 15px;border-radius: 100px;background-color: #ebeef5;overflow: hidden;position: relative;vertical-align: middle;}
          .pl-progress-inner{ position: absolute;left: 0;top: 0;background-color: #409eff;text-align: right;border-radius: 100px;line-height: 1;white-space: nowrap;transition: width .6s ease;}
          .pl-progress-inner-text { display: inline-block;vertical-align: middle;color: #d1d1d1;font-size: 12px;margin: 0 5px;height: 15px}
          .pl-progress-tip{ flex:1;text-align:right}
          .pl-progress-how{ flex: 0 0 90px; background: #ddd; border-radius: 3px; margin-left: 10px; cursor: pointer; text-align: center;}
          .pl-progress-stop{ flex: 0 0 50px; padding: 0 10px; background: #cc3235; color: #fff; border-radius: 3px; cursor: pointer;margin-left:10px;height:20px}
          .pl-progress-inner-text:after { display: inline-block;content: "";height: 100%;vertical-align: middle;}
          .pl-btn-primary { background: ${color}; border: 0; border-radius: 4px; color: #ffffff; cursor: pointer; font-size: 12px; outline: none; display:flex; align-items: center; justify-content: center; margin: 2px 0; padding: 6px 0;transition: 0.3s opacity; }
          .pl-btn-primary:hover { opacity: 0.9;transition: 0.3s opacity; }
          .pl-btn-success { background: #55af28; animation: easeOpacity 1.2s 2; animation-fill-mode:forwards }
          .pl-btn-info { background: #606266; }
          .pl-btn-warning { background: #da9328; }
          .pl-btn-warning { background: #da9328; }
          .pl-btn-danger { background: #cc3235; }
          .ali-button {display: inline-flex;align-items: center;justify-content: center;border: 0 solid transparent;border-radius: 5px;box-shadow: 0 0 0 0 transparent;width: fit-content;white-space: nowrap;flex-shrink: 0;font-size: 14px;line-height: 1.5;outline: 0;touch-action: manipulation;transition: background .3s ease,color .3s ease,border .3s ease,box-shadow .3s ease;color: #fff;background: rgb(99 125 255);margin-left: 20px;padding: 1px 12px;position: relative; cursor:pointer; height: 32px;}
          .ali-button:hover {background: rgb(122, 144, 255)}
          .tianyi-button {margin-right: 20px; padding: 4px 12px; border-radius: 4px; color: #fff; font-size: 12px; border: 1px solid #0073e3; background: #2b89ea; cursor: pointer; position: relative;}
          .tianyi-button:hover {border-color: #1874d3; background: #3699ff;}
          .yidong-button {float: left; position: relative; margin: 20px 24px 20px 0; width: 98px; height: 36px; background: #3181f9; border-radius: 2px; font-size: 14px; color: #fff; line-height: 39px; text-align: center; cursor: pointer;}
          .yidong-share-button {display: inline-block; position: relative; font-size: 14px; line-height: 36px; height: 36px; text-align: center; color: #fff; border: 1px solid #5a9afa; border-radius: 2px; padding: 0 24px; margin-left: 24px; background: #3181f9; cursor: pointer;}
          .yidong-button:hover {background: #2d76e5;}
          .xunlei-button {display: inline-flex;align-items: center;justify-content: center;border: 0 solid transparent;border-radius: 5px;box-shadow: 0 0 0 0 transparent;width: fit-content;white-space: nowrap;flex-shrink: 0;font-size: 14px;line-height: 1.5;outline: 0;touch-action: manipulation;transition: background .3s ease,color .3s ease,border .3s ease,box-shadow .3s ease;color: #fff;background: #3f85ff;margin-left: 12px;padding: 0px 12px;position: relative; cursor:pointer; height: 36px;}
          .xunlei-button:hover {background: #619bff}
          .quark-button {display: inline-flex; align-items: center; justify-content: center; border: 1px solid #ddd; border-radius: 8px; white-space: nowrap; flex-shrink: 0; font-size: 14px; line-height: 1.5; outline: 0; color: #333; background: #fff; margin-right: 10px; padding: 0px 14px; position: relative; cursor: pointer; height: 36px;}
          .quark-button:hover { background:#f6f6f6 }
          .pl-dropdown-menu {position: absolute;right: 0;top: 30px;padding: 5px 0;color: rgb(37, 38, 43);background: #fff;z-index: 999;width: 102px;border: 1px solid #ddd;border-radius: 10px; box-shadow: 0 0 1px 1px rgb(28 28 32 / 5%), 0 8px 24px rgb(28 28 32 / 12%);}
          .pl-dropdown-menu-item { height: 30px;display: flex;align-items: center;justify-content: center;cursor:pointer }
          .pl-dropdown-menu-item:hover { background-color: rgba(132,133,141,0.08);}
          .pl-button .pl-dropdown-menu { display: none; }
          .pl-button:hover .pl-dropdown-menu { display: block!important; }
          .pl-button-init { opacity: 0.5; animation: easeInitOpacity 1.2s 3; animation-fill-mode:forwards }
           @keyframes easeInitOpacity { from { opacity: 0.5; } 50% { opacity: 1 } to { opacity: 0.5; } }
           @keyframes easeOpacity { from { opacity: 1; } 50% { opacity: 0.35 } to { opacity: 1; } }
          .element-clicked { opacity: 0.5; }
          .pl-extra { margin-top: 10px;display:flex}
          .pl-extra button { flex: 1}
          .pointer { cursor:pointer }
          .pl-setting-label { display: flex;align-items: center;justify-content: space-between;padding-top: 10px; }
          .pl-label { flex: 0 0 100px;text-align:left; }
          .pl-input { flex: 1; padding: 8px 10px; border: 1px solid #c2c2c2; border-radius: 5px; font-size: 14px }
          .pl-color { flex: 1;display: flex;flex-wrap: wrap; margin-right: -10px;}
          .pl-color-box { width: 35px;height: 35px;margin:10px 10px 0 0;; box-sizing: border-box;border:1px solid #fff;cursor:pointer }
          .pl-color-box.checked { border:3px dashed #111!important }
          .pl-close:focus { outline: 0; box-shadow: none; }
          .tag-danger {color:#cc3235;margin: 0 5px;}
          .pl-tooltip { position: absolute; color: #ffffff; max-width: 600px; font-size: 12px; padding: 5px 10px; background: #333; border-radius: 5px; z-index: 110000; line-height: 1.3; display:none; word-break: break-all;}
           @keyframes load { 0% { transform: rotate(0deg) } 100% { transform: rotate(360deg) } }
          .pl-loading-box > div > div { position: absolute;border-radius: 50%;}
          .pl-loading-box > div > div:nth-child(1) { top: 9px;left: 9px;width: 82px;height: 82px;background: #ffffff;}
          .pl-loading-box > div > div:nth-child(2) { top: 14px;left: 38px;width: 25px;height: 25px;background: #666666;animation: load 1s linear infinite;transform-origin: 12px 36px;}
          .pl-loading { width: 16px;height: 16px;display: inline-block;overflow: hidden;background: none;}
          .pl-loading-box { width: 100%;height: 100%;position: relative;transform: translateZ(0) scale(0.16);backface-visibility: hidden;transform-origin: 0 0;}
          .pl-loading-box div { box-sizing: content-box; }
          .swal2-container { z-index:100000!important; }
          body.swal2-height-auto { height: inherit!important; }
          .btn-operate .btn-main { display:flex; align-items:center; }
          `;
      this.addStyle("panlinker-style", "style", css);
    },

    async initDialog() {
      let secret = "请输入暗号：" + pan.num;
      let result = await Swal.fire({
        title: pan.init[0],
        html: `<div>
              <img style="width: 250px;margin-bottom: 10px;" src="${pan.img}" alt="${pan.img}">
              <input class="swal2-input" id="init" type="text" placeholder="${secret}">
              <div>脚本推荐：<a target="_blank" href="https://greasyfork.org/zh-CN/scripts/499582-%E5%85%8D%E8%B4%B9%E8%8A%82%E7%82%B9-%E7%A7%91%E5%AD%A6%E4%B8%8A%E7%BD%91-%E5%85%8D%E8%B4%B9%E6%A2%AF%E5%AD%90-%E5%85%8D%E8%B4%B9%E6%9C%BA%E5%9C%BA-ssr-v2ray-clash%E5%85%8D%E8%B4%B9%E8%8A%82%E7%82%B9%E8%AE%A2%E9%98%85%E5%9C%B0%E5%9D%80%E5%88%86%E4%BA%AB-%E7%9B%B4%E8%BF%9Efacebookgoogleyoutube-%E5%B0%BD%E6%83%85%E7%9C%8B%E8%A7%86%E9%A2%91%E7%BD%91%E7%AB%99-%E6%B5%81%E9%87%8F%E7%94%A8%E4%B8%8D%E7%8E%A9">免费节点，科学上网，免费梯子，免费机场，ssr/v2ray/clash免费节点订阅地址分享，直连facebookgoogleyoutube，尽情看视频网站，流量用不玩。</a></div>
              </div>`,
        allowOutsideClick: false,
        showCloseButton: true,
        confirmButtonText: "确定",
      });
      if (result.isDismissed && result.dismiss === "close") return;
      if (pan.num === $("#init").val() || pan.license === $("#init").val()) {
        base.setValue("setting_init_code", pan.num);
        base.setValue("license", pan.license);
        message.success(pan.init[2]);
        setTimeout(() => {
          history.go(0);
        }, 1500);
      } else {
        await Swal.fire({
          title: pan.init[3],
          text: pan.init[4],
          confirmButtonText: "重新输入",
          imageUrl: pan.img,
        });
        await this.initDialog();
      }
    },
  };

  let baidu = {
    _getExtra() {
      let seKey = decodeURIComponent(base.getCookie("BDCLND"));
      return "{" + '"sekey":"' + seKey + '"' + "}";
    },

    _getSurl() {
      let reg = /(?<=s\/|surl=)([a-zA-Z0-9_-]+)/g;
      if (reg.test(location.href)) {
        return location.href.match(reg)[0];
      }
      return "";
    },

    _getFidList() {
      let fidlist = [];
      selectList.forEach((v) => {
        if (+v.isdir === 1) return;
        fidlist.push(v.fs_id);
      });
      return "[" + fidlist + "]";
    },

    _resetData() {
      progress = {};
      $.each(request, (key) => {
        request[key].abort();
      });
      $.each(ins, (key) => {
        clearInterval(ins[key]);
      });
      idm = {};
      ins = {};
      request = {};
    },

    setBDUSS() {
      try {
        GM_cookie &&
          GM_cookie("list", { name: "BDUSS" }, (cookies, error) => {
            if (!error) {
              let BDUSS = cookies?.[0]?.value;
              if (BDUSS) {
                base.setStorage("baiduyunPlugin_BDUSS", { BDUSS });
              }
            }
          });
      } catch (e) {}
    },

    getBDUSS() {
      let baiduyunPlugin_BDUSS = base.getStorage("baiduyunPlugin_BDUSS") ? base.getStorage("baiduyunPlugin_BDUSS") : '{"baiduyunPlugin_BDUSS":""}';
      return baiduyunPlugin_BDUSS.BDUSS || "";
    },

    convertLinkToAria(link, filename, ua) {
      let BDUSS = this.getBDUSS();
      if (!!BDUSS) {
        filename = base.fixFilename(filename);
        return encodeURIComponent(`aria2c "${link}" --out "${filename}" --header "User-Agent: ${ua}" --header "Cookie: BDUSS=${BDUSS}"`);
      }
      return {
        link: pan.assistant,
        text: pan.init[5],
      };
    },

    convertLinkToBC(link, filename, ua) {
      let BDUSS = this.getBDUSS();
      if (!!BDUSS) {
        let cookie = `BDUSS=${BDUSS}`;
        let bc = `AA/${encodeURIComponent(filename)}/?url=${encodeURIComponent(link)}&cookie=${encodeURIComponent(cookie)}&user_agent=${encodeURIComponent(ua)}ZZ`;
        return encodeURIComponent(`bc://http/${base.e(bc)}`);
      }
      return {
        link: pan.assistant,
        text: pan.init[5],
      };
    },

    convertLinkToCurl(link, filename, ua) {
      let BDUSS = this.getBDUSS();
      if (!!BDUSS) {
        let terminal = base.getValue("setting_terminal_type");
        filename = base.fixFilename(filename);
        return encodeURIComponent(`${terminal !== "wp" ? "curl" : "curl.exe"} -L -C - "${link}" -o "${filename}" -A "${ua}" -b "BDUSS=${BDUSS}"`);
      }
      return {
        link: pan.assistant,
        text: pan.init[5],
      };
    },

    addPageListener() {
      function _factory(e) {
        let target = $(e.target);
        let item = target.parents(".pl-item");
        let link = item.find(".pl-item-link");
        let progress = item.find(".pl-item-progress");
        let tip = item.find(".pl-item-tip");
        return {
          item,
          link,
          progress,
          tip,
          target,
        };
      }

      function _reset(i) {
        ins[i] && clearInterval(ins[i]);
        request[i] && request[i].abort();
        progress[i] = 0;
        idm[i] = false;
      }

      doc.on("mouseenter mouseleave click", ".pl-button.g-dropdown-button", (e) => {
        if (e.type === "mouseleave") {
          $(e.currentTarget).removeClass("button-open");
        } else {
          $(e.currentTarget).addClass("button-open");
          $(e.currentTarget).find(".pl-dropdown-menu").show();
        }
      });
      doc.on("mouseleave", ".pl-button.g-dropdown-button .pl-dropdown-menu", (e) => {
        $(e.currentTarget).hide();
      });

      doc.on("click", ".pl-button-mode", (e) => {
        mode = e.target.dataset.mode;
        Swal.showLoading();
        this.getPCSLink();
      });
      doc.on("click", ".listener-link-api", async (e) => {
        e.preventDefault();
        let o = _factory(e);
        let $width = o.item.find(".pl-progress-inner");
        let $text = o.item.find(".pl-progress-inner-text");
        let filename = o.link[0].dataset.filename;
        let index = o.link[0].dataset.index;
        _reset(index);
        base.get(o.link[0].dataset.link, { "User-Agent": pan.ua }, "blob", { filename, index });
        ins[index] = setInterval(() => {
          let prog = +progress[index] || 0;
          let isIDM = idm[index] || false;
          if (isIDM) {
            o.tip.hide();
            o.progress.hide();
            o.link.text("已成功唤起IDM，请查看IDM下载框！").animate({ opacity: "0.5" }, "slow").show();
            clearInterval(ins[index]);
            idm[index] = false;
          } else {
            o.link.hide();
            o.tip.hide();
            o.progress.show();
            $width.css("width", prog + "%");
            $text.text(prog + "%");
            if (prog === 100) {
              clearInterval(ins[index]);
              progress[index] = 0;
              o.item.find(".pl-progress-stop").hide();
              o.item.find(".pl-progress-tip").html("下载完成，正在弹出浏览器下载框！");
            }
          }
        }, 500);
      });
      doc.on("click", ".listener-retry", async (e) => {
        let o = _factory(e);
        o.tip.hide();
        o.link.show();
      });
      doc.on("click", ".listener-how", async (e) => {
        let o = _factory(e);
        let index = o.link[0].dataset.index;
        if (request[index]) {
          request[index].abort();
          clearInterval(ins[index]);
          o.progress.hide();
          o.tip.show();
        }
      });
      doc.on("click", ".listener-stop", async (e) => {
        let o = _factory(e);
        let index = o.link[0].dataset.index;
        if (request[index]) {
          request[index].abort();
          clearInterval(ins[index]);
          o.tip.hide();
          o.progress.hide();
          o.link.show(0);
        }
      });
      doc.on("click", ".listener-back", async (e) => {
        let o = _factory(e);
        o.tip.hide();
        o.link.show();
      });
      doc.on("click", ".listener-link-aria, .listener-copy-all", (e) => {
        e.preventDefault();
        if (!e.target.dataset.link) {
          $(e.target).removeClass("listener-copy-all").addClass("pl-btn-danger").html(`${pan.init[5]}👉<a href="${pan.assistant}" target="_blank" class="pl-a">点击此处安装</a>👈`);
        } else {
          base.setClipboard(decodeURIComponent(e.target.dataset.link));
          $(e.target).text("复制成功，快去粘贴吧！").animate({ opacity: "0.5" }, "slow");
        }
      });
      doc.on("click", ".listener-link-rpc", async (e) => {
        let target = $(e.currentTarget);
        target.find(".icon").remove();
        target.find(".pl-loading").remove();
        target.prepend(base.createLoading());
        let res = await this.sendLinkToRPC(e.currentTarget.dataset.filename, e.currentTarget.dataset.link);
        if (res === "success") {
          $(".listener-rpc-task").show();
          target.removeClass("pl-btn-danger").html("发送成功，快去看看吧！").animate({ opacity: "0.5" }, "slow");
        } else if (res === "assistant") {
          target.addClass("pl-btn-danger").html(`${pan.init[5]}👉<a href="${pan.assistant}" target="_blank" class="pl-a">点击此处安装</a>👈`);
        } else {
          target.addClass("pl-btn-danger").text("发送失败，请检查您的RPC配置信息！").animate({ opacity: "0.5" }, "slow");
        }
      });
      doc.on("click", ".listener-send-rpc", (e) => {
        $(".listener-link-rpc").click();
        $(e.target).text("发送完成，发送结果见上方按钮！").animate({ opacity: "0.5" }, "slow");
      });
      doc.on("click", ".listener-open-setting", () => {
        base.showSetting();
      });
      doc.on("click", ".listener-rpc-task", () => {
        let rpc = JSON.stringify({
            domain: base.getValue("setting_rpc_domain"),
            port: base.getValue("setting_rpc_port"),
          }),
          url = `${pan.d}/?rpc=${base.e(rpc)}#${base.getValue("setting_rpc_token")}`;
        GM_openInTab(url, { active: true });
      });
      document.documentElement.addEventListener(
        "mouseup",
        (e) => {
          if (e.target.nodeName === "A" && ~e.target.className.indexOf("pl-a")) {
            e.stopPropagation();
          }
        },
        true
      );
    },

    addButton() {
      if (!pt) return;
      let $toolWrap;
      let $button = $(
        `<div class="g-dropdown-button pointer pl-button"><div style="color:#fff;background: ${color};border-color:${color}" class="g-button g-button-blue"><span class="g-button-right"><em class="icon icon-download"></em><span class="text" style="width: 60px;">下载助手</span></span></div><div class="menu" style="width:auto;z-index:41;border-color:${color}"><div style="color:${color}" class="g-button-menu pl-button-mode" data-mode="api">API下载</div><div style="color:${color}" class="g-button-menu pl-button-mode" data-mode="aria">Aria下载</div><div style="color:${color}" class="g-button-menu pl-button-mode" data-mode="rpc">RPC下载</div><div style="color:${color}" class="g-button-menu pl-button-mode" data-mode="curl">cURL下载</div><div style="color:${color}" class="g-button-menu pl-button-mode" data-mode="bc">BC下载</div><li class="g-button-menu pl-button-mode listener-open-setting">助手设置</li>${
          pan.code == 200 && version < pan.version ? pan.new : ""
        }</div></div>`
      );
      if (pt === "home") $toolWrap = $(pan.btn.home);
      if (pt === "main") {
        $toolWrap = $(pan.btn.main);
        $button = $(
          `<div class="pl-button" style="position: relative; display: inline-block; margin-right: 8px;"><button class="u-button u-button--primary u-button--small is-round is-has-icon" style="background: ${color};border-color: ${color};font-size: 14px; padding: 8px 16px; border: none;"><i class="u-icon u-icon-download"></i><span>下载助手</span></button><ul class="dropdown-list nd-common-float-menu pl-dropdown-menu"><li class="sub cursor-p pl-button-mode" data-mode="api">API下载</li><li class="sub cursor-p pl-button-mode" data-mode="aria">Aria下载</li><li class="sub cursor-p pl-button-mode" data-mode="rpc">RPC下载</li><li class="sub cursor-p pl-button-mode" data-mode="curl">cURL下载</li><li class="sub cursor-p pl-button-mode" data-mode="bc" >BC下载</li><li class="sub cursor-p pl-button-mode listener-open-setting">助手设置</li>${
            pan.code == 200 && version < pan.version ? pan.newX : ""
          }</ul></div>`
        );
      }
      if (pt === "share") $toolWrap = $(pan.btn.share);
      $toolWrap.prepend($button);
      this.setBDUSS();
      this.addPageListener();
    },

    addInitButton() {
      if (!pt) return;
      let $toolWrap;
      let $button = $(
        `<div class="g-dropdown-button pointer pl-button-init" style="opacity:.5"><div style="color:#fff;background: ${color};border-color:${color}" class="g-button g-button-blue"><span class="g-button-right"><em class="icon icon-download"></em><span class="text" style="width: 60px;">下载助手</span></span></div></div>`
      );
      if (pt === "home") $toolWrap = $(pan.btn.home);
      if (pt === "main") {
        $toolWrap = $(pan.btn.main);
        $button = $(
          `<div class="pl-button-init" style="opacity:.5; display: inline-block; margin-right: 8px;"><button class="u-button u-button--primary u-button--small is-round is-has-icon" style="background: ${color};border-color: ${color};font-size: 14px; padding: 8px 16px; border: none;"><i class="u-icon u-icon-download"></i><span>下载助手</span></button></div>`
        );
      }
      if (pt === "share") $toolWrap = $(pan.btn.share);
      $toolWrap.prepend($button);
      $button.click(() => base.initDialog());
    },

    async getToken() {
      const openTab = () => {
        GM_openInTab(pan.pcs[3], { active: false, insert: true, setParent: true });
        base.deleteValue("baidu_access_token");
      };

      const waitForToken = () =>
        new Promise((resolve) => {
          let attempts = 0;
          const interval = setInterval(() => {
            const token = base.getValue("baidu_access_token");
            if (token) {
              clearInterval(interval);
              resolve(token);
            }
            attempts++;
            if (attempts > 60) {
              clearInterval(interval);
              resolve("");
            }
          }, 1000);
        });

      if (manageHandler === "Tampermonkey" && base.getMajorVersion(manageVersion) >= 5) {
        openTab();
        return waitForToken();
      }
      let res = await base.getFinalUrl(pan.pcs[3]);

      if (!res.includes("authorize") && !res.includes("access_token=")) {
        openTab();
        return waitForToken();
      }
      if (res.includes("authorize")) {
        let html = await base.get(pan.pcs[3], {}, "text");
        let bdstoken = html.match(/name="bdstoken"\s+value="([^"]+)"/)?.[1];
        let client_id = html.match(/name="client_id"\s+value="([^"]+)"/)?.[1];
        let data = {
          grant_permissions_arr: "netdisk",
          bdstoken: bdstoken,
          client_id: client_id,
          response_type: "token",
          display: "page",
          grant_permissions: "basic,netdisk",
        };
        await base.post(pan.pcs[3], base.stringify(data), {
          "Content-Type": "application/x-www-form-urlencoded",
        });
        let res2 = await base.getFinalUrl(pan.pcs[3]);
        let accessToken = res2.match(/access_token=([^&]+)/)?.[1];
        accessToken && base.setValue("baidu_access_token", accessToken);
        return accessToken;
      }
      let accessToken = res.match(/access_token=([^&]+)/)?.[1];
      accessToken && base.setValue("baidu_access_token", accessToken);
      return accessToken;
    },

    async getPCSLink(maxRequestTime = 1) {
      selectList = this.getSelectedList();
      let fidList = this._getFidList(),
        url,
        res;

      if (pt === "home" || pt === "main") {
        if (selectList.length === 0) {
          return message.error("提示：请先勾选要下载的文件！");
        }
        if (fidList.length === 2) {
          return message.error("提示：请打开文件夹后勾选文件！");
        }
        fidList = encodeURIComponent(fidList);
        let accessToken = base.getValue("baidu_access_token") || (await this.getToken());
        url = `${pan.pcs[0]}&fsids=${fidList}&access_token=${accessToken}`;
        res = await base.get(url, { "User-Agent": pan.ua });
      }
      if (pt === "share") {
        this.getShareData();
        if (!params.bdstoken) {
          return message.error("提示：请先登录网盘！");
        }
        if (selectList.length === 0) {
          return message.error("提示：请先勾选要下载的文件！");
        }
        if (fidList.length === 2) {
          return message.error("提示：请打开文件夹后勾选文件！");
        }
        let dialog = await Swal.fire({
          toast: true,
          icon: "info",
          title: `提示：请将文件<span class="tag-danger">[保存到网盘]</span>👉前往<span class="tag-danger">[我的网盘]</span>中下载！`,
          showConfirmButton: true,
          confirmButtonText: "点击保存",
          position: "top",
        });
        if (dialog.isConfirmed) {
          $(".tools-share-save-hb")[0].click();
        }
        return;
      }
      if (res.errno === 0) {
        let html = this.generateDom(res.list);
        this.showMainDialog(pan[mode][0], html, pan[mode][1]);
      } else if (res.errno === 112) {
        return message.error("提示：页面过期，请刷新重试！");
      } else if (res.errno === 9019) {
        maxRequestTime--;
        await this.getToken();
        if (maxRequestTime > 0) {
          await this.getPCSLink(maxRequestTime);
        } else {
          message.error("提示：获取下载链接失败！请刷新网页后重试！");
        }
      } else {
        base.deleteValue("baidu_access_token");
        message.error("提示：获取下载链接失败！请刷新网页后重试！");
      }
    },

    generateDom(list) {
      let content = '<div class="pl-main">';
      let alinkAllText = "";
      base.sortByName(list);
      list.forEach((v, i) => {
        if (v.isdir === 1) return;
        let filename = v.server_filename || v.filename;
        let ext = base.getExtension(filename);
        let size = base.sizeFormat(v.size);
        let dlink = v.dlink + "&access_token=" + base.getValue("baidu_access_token");
        if (mode === "api") {
          $X.runcmd(`IDMan /n /d "${dlink}" /f "${filename}" /p "D:\\Download\\Pan"`);
          console.log(dlink);
          content += `<div class="pl-item">
                              <div class="pl-item-name listener-tip" data-size="${size}">${filename}</div>
                              <a class="pl-item-link pl-a listener-link-api" href="${dlink}" data-filename="${filename}" data-link="${dlink}" data-index="${i}">${dlink}</a>
                              <div class="pl-item-tip" style="display: none"><span>若没有弹出IDM下载框，找到IDM <b>选项</b> -> <b>文件类型</b> -> <b>第一个框</b> 中添加后缀 <span class="pl-ext">${ext}</span>，<a href="${pan.idm}" target="_blank" class="pl-a">详见此处</a></span> <span class="pl-back listener-back">返回</span></div>
                              <div class="pl-item-progress" style="display: none">
                                  <div class="pl-progress">
                                      <div class="pl-progress-outer"></div>
                                      <div class="pl-progress-inner" style="width:5%">
                                        <div class="pl-progress-inner-text">0%</div>
                                      </div>
                                  </div>
                                  <span class="pl-progress-stop listener-stop">取消下载</span>
                                  <span class="pl-progress-tip">未发现IDM，使用自带浏览器下载</span>
                                  <span class="pl-progress-how listener-how">如何唤起IDM？</span>
                              </div></div>`;
        }
        if (mode === "aria") {
          let alink = this.convertLinkToAria(dlink, filename, pan.ua);
          if (typeof alink === "object") {
            content += `<div class="pl-item">
                              <div class="pl-item-name listener-tip" data-size="${size}">${filename}</div>
                              <a class="pl-item-link pl-a" target="_blank" href="${alink.link}" data-filename="${filename}" data-link="${alink.link}">${decodeURIComponent(alink.text)}</a> </div>`;
          } else {
            alinkAllText += alink + "\r\n";
            content += `<div class="pl-item">
                              <div class="pl-item-name listener-tip" data-size="${size}">${filename}</div>
                              <a class="pl-item-link pl-a listener-link-aria" href="${alink}" title="点击复制aria2c链接" data-filename="${filename}" data-link="${alink}">${decodeURIComponent(alink)}</a> </div>`;
          }
        }
        if (mode === "rpc") {
          content += `<div class="pl-item">
                              <div class="pl-item-name listener-tip" data-size="${size}">${filename}</div>
                              <button class="pl-item-link listener-link-rpc pl-btn-primary pl-btn-info" data-filename="${filename}" data-link="${dlink}"><em class="icon icon-device"></em><span style="margin-left: 5px;">推送到 RPC 下载器</span></button></div>`;
        }
        if (mode === "curl") {
          let alink = this.convertLinkToCurl(dlink, filename, pan.ua);
          if (typeof alink === "object") {
            content += `<div class="pl-item">
                              <div class="pl-item-name listener-tip" data-size="${size}">${filename}</div>
                              <a class="pl-item-link pl-a" target="_blank" href="${alink.link}" data-filename="${filename}" data-link="${alink.link}">${decodeURIComponent(alink.text)}</a> </div>`;
          } else {
            alinkAllText += alink + "\r\n";
            content += `<div class="pl-item">
                              <div class="pl-item-name listener-tip" data-size="${size}">${filename}</div>
                              <a class="pl-item-link pl-a listener-link-aria" href="${alink}" title="点击复制curl链接" data-filename="${filename}" data-link="${alink}">${decodeURIComponent(alink)}</a> </div>`;
          }
        }
        if (mode === "bc") {
          let alink = this.convertLinkToBC(dlink, filename, pan.ua);
          if (typeof alink === "object") {
            content += `<div class="pl-item">
                              <div class="pl-item-name listener-tip" data-size="${size}">${filename}</div>
                              <a class="pl-item-link pl-a" target="_blank" href="${alink.link}" data-filename="${filename}" data-link="${alink.link}">${decodeURIComponent(alink.text)}</a> </div>`;
          } else {
            content += `<div class="pl-item">
                              <div class="pl-item-name listener-tip" data-size="${size}">${filename}</div>
                              <a class="pl-item-link pl-a" href="${decodeURIComponent(alink)}" title="点击用比特彗星下载" data-filename="${filename}" data-link="${alink}">${decodeURIComponent(alink)}</a> </div>`;
          }
        }
      });
      content += "</div>";
      if (mode === "aria") content += `<div class="pl-extra"><button class="pl-btn-primary listener-copy-all" data-link="${alinkAllText}">复制全部链接</button></div>`;
      if (mode === "rpc") {
        let rpc = base.getValue("setting_rpc_domain") + ":" + base.getValue("setting_rpc_port") + base.getValue("setting_rpc_path");
        content += `<div class="pl-extra"><button class="pl-btn-primary listener-send-rpc">发送全部链接</button><button title="${rpc}" class="pl-btn-primary pl-btn-warning listener-open-setting" style="margin-left: 10px">设置 RPC 参数（当前为：${rpc}）</button><button class="pl-btn-primary pl-btn-success listener-rpc-task" style="margin-left: 10px;display: none">查看下载任务</button></div>`;
      }
      if (mode === "curl")
        content += `<div class="pl-extra"><button class="pl-btn-primary listener-copy-all" data-link="${alinkAllText}">复制全部链接</button><button class="pl-btn-primary pl-btn-warning listener-open-setting" style="margin-left: 10px;">设置终端类型（当前为：${
          terminalType[base.getValue("setting_terminal_type")]
        }）</button></div>`;
      return content;
    },

    async sendLinkToRPC(filename, link) {
      let rpc = {
        domain: base.getValue("setting_rpc_domain"),
        port: base.getValue("setting_rpc_port"),
        path: base.getValue("setting_rpc_path"),
        token: base.getValue("setting_rpc_token"),
        dir: base.getValue("setting_rpc_dir"),
      };
      let BDUSS = this.getBDUSS();
      if (!BDUSS) return "assistant";

      let url = `${rpc.domain}:${rpc.port}${rpc.path}`;
      let rpcData = {
        id: new Date().getTime(),
        jsonrpc: "2.0",
        method: "aria2.addUri",
        params: [
          `token:${rpc.token}`,
          [link],
          {
            dir: rpc.dir,
            out: filename,
            header: [`User-Agent: ${pan.ua}`, `Cookie: BDUSS=${BDUSS}`],
          },
        ],
      };
      try {
        let res = await base.post(url, rpcData, { "User-Agent": pan.ua }, "");
        if (res.result) return "success";
        return "fail";
      } catch (e) {
        return "fail";
      }
    },

    getSelectedList() {
      try {
        return require("system-core:context/context.js").instanceForSystem.list.getSelected();
      } catch (e) {
        return document.querySelector(".wp-s-core-pan").__vue__.selectedList;
      }
    },

    getLogid() {
      let ut = require("system-core:context/context.js").instanceForSystem.tools.baseService;
      return ut.base64Encode(base.getCookie("BAIDUID"));
    },

    getShareData() {
      let res = locals.dump();
      params.shareType = "secret";
      params.sign = "";
      params.timestamp = "";
      params.bdstoken = res.bdstoken.value;
      params.channel = "chunlei";
      params.clienttype = 0;
      params.web = 1;
      params.app_id = 250528;
      params.encrypt = 0;
      params.product = "share";
      params.logid = this.getLogid();
      params.primaryid = res.shareid.value;
      params.uk = res.share_uk.value;
      params.shareType === "secret" && (params.extra = this._getExtra());
      params.surl = this._getSurl();
    },

    detectPage() {
      let path = location.pathname;
      if (/^\/disk\/home/.test(path)) return "home";
      if (/^\/disk\/main/.test(path)) return "main";
      if (/^\/(s|share)\//.test(path)) return "share";
      return "";
      return "";
    },

    showMainDialog(title, html, footer) {
      Swal.fire({
        title,
        html,
        footer,
        allowOutsideClick: false,
        showCloseButton: true,
        showConfirmButton: false,
        position: "top",
        width,
        padding: "15px 20px 5px",
        customClass,
      }).then(() => {
        this._resetData();
      });
    },

    async initPanLinker() {
      base.initDefaultConfig();
      base.addPanLinkerStyle();
      pt = this.detectPage();
      let res = await base.post(`https://api.youxiaohou.com/config/v2?ver=${version}&a=${author}`, {}, {}, "text");
      pan = JSON.parse(base.d(res));
      Object.freeze && Object.freeze(pan);
      pan.num === base.getValue("setting_init_code") || pan.license === base.getValue("license") ? this.addButton() : this.addInitButton();
      base.createTip();
      base.registerMenuCommand();
    },

    async initAuthorize() {
      let ins = setInterval(() => {
        if (/openapi.baidu.com\/oauth\/2.0\/authorize/.test(location.href)) {
          let confirmButton = document.querySelector("#auth-allow");
          if (confirmButton) {
            confirmButton.click();
            return;
          }
        }
        if (/openapi.baidu.com\/oauth\/2.0\/login_success/.test(location.href)) {
          if (location.href.includes("access_token")) {
            let token = location.href.match(/access_token=(.*?)&/)[1];
            base.setValue("baidu_access_token", token);
            window.close();
          }
        }
      }, 200);
    },
  };

  let ali = {
    convertLinkToAria(link, filename, ua) {
      filename = base.fixFilename(filename);
      return encodeURIComponent(`aria2c "${link}" --out "${filename}" --header "Referer: https://www.aliyundrive.com/"`);
    },

    convertLinkToBC(link, filename, ua) {
      let bc = `AA/${encodeURIComponent(filename)}/?url=${encodeURIComponent(link)}&refer=${encodeURIComponent("https://www.aliyundrive.com/")}ZZ`;
      return encodeURIComponent(`bc://http/${base.e(bc)}`);
    },

    convertLinkToCurl(link, filename, ua) {
      let terminal = base.getValue("setting_terminal_type");
      filename = base.fixFilename(filename);
      return encodeURIComponent(`${terminal !== "wp" ? "curl" : "curl.exe"} -L -C - "${link}" -o "${filename}" -e "https://www.aliyundrive.com/"`);
    },

    addPageListener() {
      doc.on("click", ".pl-button-mode", (e) => {
        mode = e.target.dataset.mode;
        Swal.showLoading();
        this.getPCSLink();
      });
      doc.on("click", ".listener-link-api", async (e) => {
        e.preventDefault();
        let dataset = e.currentTarget.dataset;
        let href = dataset.link;
        // let url = await this.getRealLink(dataset.did, dataset.fid);
        // if (url) href = url;
        $("#downloadIframe").attr("src", href);
        // let d = document.createElement("a");
        // d.download = e.currentTarget.dataset.filename;
        // d.rel = "noopener";
        // d.href = href;
        // d.dispatchEvent(new MouseEvent("click"));
      });
      doc.on("click", ".listener-link-api-btn", async (e) => {
        base.setClipboard(e.target.dataset.filename);
        $(e.target).text("复制成功").animate({ opacity: "0.5" }, "slow");
      });
      doc.on("click", ".listener-link-aria, .listener-copy-all", (e) => {
        e.preventDefault();
        base.setClipboard(decodeURIComponent(e.target.dataset.link));
        $(e.target).text("复制成功，快去粘贴吧！").animate({ opacity: "0.5" }, "slow");
      });
      doc.on("click", ".listener-link-rpc", async (e) => {
        let target = $(e.currentTarget);
        target.find(".icon").remove();
        target.find(".pl-loading").remove();
        target.prepend(base.createLoading());
        let res = await this.sendLinkToRPC(e.currentTarget.dataset.filename, e.currentTarget.dataset.link);
        if (res === "success") {
          $(".listener-rpc-task").show();
          target.removeClass("pl-btn-danger").html("发送成功，快去看看吧！").animate({ opacity: "0.5" }, "slow");
        } else {
          target.addClass("pl-btn-danger").text("发送失败，请检查您的RPC配置信息！").animate({ opacity: "0.5" }, "slow");
        }
      });
      doc.on("click", ".listener-send-rpc", (e) => {
        $(".listener-link-rpc").click();
        $(e.target).text("发送完成，发送结果见上方按钮！").animate({ opacity: "0.5" }, "slow");
      });
      doc.on("click", ".listener-open-setting", () => {
        base.showSetting();
      });
      doc.on("click", ".listener-rpc-task", () => {
        let rpc = JSON.stringify({
            domain: base.getValue("setting_rpc_domain"),
            port: base.getValue("setting_rpc_port"),
          }),
          url = `${pan.d}/?rpc=${base.e(rpc)}#${base.getValue("setting_rpc_token")}`;
        GM_openInTab(url, { active: true });
      });
    },

    async getRealLink(d, f) {
      let authorization = `${base.getStorage("token").token_type} ${base.getStorage("token").access_token}`;
      let res = await base.post(
        pan.pcs[1],
        {
          drive_id: d,
          file_id: f,
        },
        {
          authorization,
          "content-type": "application/json;charset=utf-8",
          referer: "https://www.aliyundrive.com/",
          "x-canary": "client=windows,app=adrive,version=v6.0.0",
        }
      );
      if (res.code === "AccessTokenInvalid") {
        return message.error("提示：Token过期，请刷新网页后重试！");
      }
      if (res.url) {
        return res.url;
      }
      return "";
    },

    addButton() {
      if (!pt) return;
      let $toolWrap;
      let $button = $(
        `<div class="ali-button pl-button"><svg viewBox="0 0 1024 1024" xmlns="http://www.w3.org/2000/svg" width="16" height="16"><path d="M853.333 938.667H170.667a85.333 85.333 0 0 1-85.334-85.334v-384A85.333 85.333 0 0 1 170.667 384H288a32 32 0 0 1 0 64H170.667a21.333 21.333 0 0 0-21.334 21.333v384a21.333 21.333 0 0 0 21.334 21.334h682.666a21.333 21.333 0 0 0 21.334-21.334v-384A21.333 21.333 0 0 0 853.333 448H736a32 32 0 0 1 0-64h117.333a85.333 85.333 0 0 1 85.334 85.333v384a85.333 85.333 0 0 1-85.334 85.334z" fill="#fff"/><path d="M715.03 543.552a32.81 32.81 0 0 0-46.251 0L554.005 657.813v-540.48a32 32 0 0 0-64 0v539.734L375.893 543.488a32.79 32.79 0 0 0-46.229 0 32.427 32.427 0 0 0 0 46.037l169.557 168.811a32.81 32.81 0 0 0 46.251 0l169.557-168.81a32.47 32.47 0 0 0 0-45.974z" fill="#FF9C00"/></svg><span>下载助手</span><ul class="pl-dropdown-menu"><li class="pl-dropdown-menu-item pl-button-mode" data-mode="api">API下载</li><li class="pl-dropdown-menu-item pl-button-mode" data-mode="aria" >Aria下载</li><li class="pl-dropdown-menu-item pl-button-mode" data-mode="rpc">RPC下载</li><li class="pl-dropdown-menu-item pl-button-mode" data-mode="curl">cURL下载</li><li class="pl-dropdown-menu-item pl-button-mode" data-mode="bc" >BC下载</li><li class="pl-dropdown-menu-item pl-button-mode listener-open-setting">助手设置</li>${
          pan.code == 200 && version < pan.version ? pan.new : ""
        }</ul></div>`
      );
      if (pt === "home") {
        base.listenElement(pan.btn.home, () => {
          $toolWrap = $(pan.btn.home);
          $(".pl-button").length === 0 && $toolWrap.append($button);
        });
      }
      if (pt === "share") {
        $button.css({ "margin-right": "10px" });
        base.listenElement(pan.btn.share, () => {
          $toolWrap = $(pan.btn.share);
          $(".pl-button").length === 0 && $toolWrap.prepend($button);
        });
      }
      base.createDownloadIframe();
      this.addPageListener();
    },

    addInitButton() {
      if (!pt) return;
      let $toolWrap;
      let $button = $(
        `<div class="ali-button pl-button-init"><svg viewBox="0 0 1024 1024" xmlns="http://www.w3.org/2000/svg" width="16" height="16"><path d="M853.333 938.667H170.667a85.333 85.333 0 0 1-85.334-85.334v-384A85.333 85.333 0 0 1 170.667 384H288a32 32 0 0 1 0 64H170.667a21.333 21.333 0 0 0-21.334 21.333v384a21.333 21.333 0 0 0 21.334 21.334h682.666a21.333 21.333 0 0 0 21.334-21.334v-384A21.333 21.333 0 0 0 853.333 448H736a32 32 0 0 1 0-64h117.333a85.333 85.333 0 0 1 85.334 85.333v384a85.333 85.333 0 0 1-85.334 85.334z" fill="#fff"/><path d="M715.03 543.552a32.81 32.81 0 0 0-46.251 0L554.005 657.813v-540.48a32 32 0 0 0-64 0v539.734L375.893 543.488a32.79 32.79 0 0 0-46.229 0 32.427 32.427 0 0 0 0 46.037l169.557 168.811a32.81 32.81 0 0 0 46.251 0l169.557-168.81a32.47 32.47 0 0 0 0-45.974z" fill="#FF9C00"/></svg><span>下载助手</span></div>`
      );
      if (pt === "home") {
        base.listenElement(pan.btn.home, () => {
          $toolWrap = $(pan.btn.home);
          $(".pl-button-init").length === 0 && $toolWrap.append($button);
        });
      }
      if (pt === "share") {
        $button.css({ "margin-right": "10px" });
        base.listenElement(pan.btn.share, () => {
          $toolWrap = $(pan.btn.share);
          $(".pl-butto-init").length === 0 && $toolWrap.prepend($button);
        });
      }
      $button.click(() => base.initDialog());
    },

    async getPCSLink() {
      let reactDomGrid = document.querySelector(pan.dom.grid);
      if (reactDomGrid) {
        let res = await Swal.fire({
          title: "提示",
          html: '<div style="display: flex;align-items: center;justify-content: center;">请先切换到 <b>列表视图</b>（<svg class="icon" viewBox="0 0 1024 1024" xmlns="http://www.w3.org/2000/svg" width="16" height="16"><path d="M132 928c-32.8 0-59.2-26.4-59.2-59.2s26.4-59.2 59.2-59.2h760c32.8 0 59.2 26.4 59.2 59.2S924.8 928 892 928H132zm0-356.8c-32.8 0-59.2-26.4-59.2-59.2s26.4-59.2 59.2-59.2h760c32.8 0 59.2 26.4 59.2 59.2s-26.4 59.2-59.2 59.2H132zm0-356c-32.8 0-59.2-26.4-59.2-59.2S99.2 96.8 132 96.8h760c32.8 0 59.2 26.4 59.2 59.2s-26.4 59.2-59.2 59.2H132z"/></svg>）后获取！</div>',
          confirmButtonText: "点击切换",
        });
        if (res) {
          document.querySelector(pan.dom.switch).click();
          return message.success("切换成功，请重新获取下载链接！");
        }
        return false;
      }
      selectList = this.getSelectedList();
      if (selectList.length === 0) {
        return message.error("提示：请先勾选要下载的文件！");
      }
      if (this.isOnlyFolder()) {
        return message.error("提示：请打开文件夹后勾选文件！");
      }
      if (pt === "share") {
        if (selectList.length > 20) {
          return message.error("提示：单次最多可勾选 20 个文件！");
        }
        try {
          let authorization = `${base.getStorage("token").token_type} ${base.getStorage("token").access_token}`;
          let xShareToken = base.getStorage("shareToken").share_token;

          for (let i = 0; i < selectList.length; i++) {
            let res = await base.post(
              pan.pcs[0],
              {
                expire_sec: 600,
                file_id: selectList[i].fileId,
                share_id: selectList[i].shareId,
              },
              {
                authorization,
                "content-type": "application/json;charset=utf-8",
                "x-share-token": xShareToken,
              }
            );
            if (res.download_url) {
              selectList[i].downloadUrl = res.download_url;
            }
          }
        } catch (e) {
          return message.error("提示：请先登录网盘！");
        }
      } else {
        if (selectList.length > 20) {
          return message.error("提示：单次最多可勾选 20 个文件！");
        }
        let noUrlSelectList = selectList.filter((v) => !Boolean(v.url));
        let queue = [];
        noUrlSelectList.forEach((item, index) => {
          queue.push(this.getRealLink(item.driveId, item.fileId));
        });

        const res = await Promise.all(queue);
        res.forEach((val, index) => {
          noUrlSelectList[index].url = val;
        });
      }
      let html = this.generateDom(selectList);
      this.showMainDialog(pan[mode][0], html, pan[mode][1]);
    },

    generateDom(list) {
      let content = '<div class="pl-main">';
      let alinkAllText = "";
      list.forEach((v, i) => {
        if (v.type === "folder") return;
        let filename = v.name;
        let fid = v.fileId;
        let did = v.driveId;
        let size = base.sizeFormat(v.size);
        let dlink = v.downloadUrl || v.url;
        if (mode === "api") {
          $X.runcmd(`IDMan /n /d "${dlink}" /f "${filename}" /p "D:\\Download\\Pan"`);
          console.log(dlink);
          content += `<div class="pl-item">
                              <div class="pl-item-name listener-tip" data-size="${size}">${filename}</div>
                              <a class="pl-item-link listener-link-api" data-did="${did}" data-fid="${fid}" data-filename="${filename}" data-link="${dlink}" data-index="${i}">${dlink}</a>
                              <div class="pl-item-btn listener-link-api-btn" data-filename="${filename}">复制文件名</div>
                              </div>`;
        }
        if (mode === "aria") {
          let alink = this.convertLinkToAria(dlink, filename, navigator.userAgent);
          alinkAllText += alink + "\r\n";
          content += `<div class="pl-item">
                              <div class="pl-item-name listener-tip" data-size="${size}">${filename}</div>
                              <a class="pl-item-link listener-link-aria" href="${alink}" title="点击复制aria2c链接" data-filename="${filename}" data-link="${alink}">${decodeURIComponent(alink)}</a> </div>`;
        }
        if (mode === "rpc") {
          content += `<div class="pl-item">
                              <div class="pl-item-name listener-tip" data-size="${size}">${filename}</div>
                              <button class="pl-item-link listener-link-rpc pl-btn-primary pl-btn-info" data-filename="${filename}" data-link="${dlink}"><em class="icon icon-device"></em><span style="margin-left: 5px;">推送到 RPC 下载器</span></button></div>`;
        }
        if (mode === "curl") {
          let alink = this.convertLinkToCurl(dlink, filename, navigator.userAgent);
          alinkAllText += alink + "\r\n";
          content += `<div class="pl-item">
                              <div class="pl-item-name listener-tip" data-size="${size}">${filename}</div>
                              <a class="pl-item-link listener-link-aria" href="${alink}" title="点击复制curl链接" data-filename="${filename}" data-link="${alink}">${decodeURIComponent(alink)}</a> </div>`;
        }
        if (mode === "bc") {
          let alink = this.convertLinkToBC(dlink, filename, navigator.userAgent);
          content += `<div class="pl-item">
                              <div class="pl-item-name listener-tip" data-size="${size}">${filename}</div>
                              <a class="pl-item-link" href="${decodeURIComponent(alink)}" title="点击用比特彗星下载" data-filename="${filename}" data-link="${alink}">${decodeURIComponent(alink)}</a> </div>`;
        }
      });
      content += "</div>";
      if (mode === "aria") content += `<div class="pl-extra"><button class="pl-btn-primary listener-copy-all" data-link="${alinkAllText}">复制全部链接</button></div>`;
      if (mode === "rpc") {
        let rpc = base.getValue("setting_rpc_domain") + ":" + base.getValue("setting_rpc_port") + base.getValue("setting_rpc_path");
        content += `<div class="pl-extra"><button class="pl-btn-primary listener-send-rpc">发送全部链接</button><button title="${rpc}" class="pl-btn-primary pl-btn-warning listener-open-setting" style="margin-left: 10px">设置 RPC 参数（当前为：${rpc}）</button><button class="pl-btn-primary pl-btn-success listener-rpc-task" style="margin-left: 10px;display: none">查看下载任务</button></div>`;
      }
      if (mode === "curl")
        content += `<div class="pl-extra"><button class="pl-btn-primary listener-copy-all" data-link="${alinkAllText}">复制全部链接</button><button class="pl-btn-primary pl-btn-warning listener-open-setting" style="margin-left: 10px;">设置终端类型（当前为：${
          terminalType[base.getValue("setting_terminal_type")]
        }）</button></div>`;
      return content;
    },

    async sendLinkToRPC(filename, link) {
      let rpc = {
        domain: base.getValue("setting_rpc_domain"),
        port: base.getValue("setting_rpc_port"),
        path: base.getValue("setting_rpc_path"),
        token: base.getValue("setting_rpc_token"),
        dir: base.getValue("setting_rpc_dir"),
      };

      let url = `${rpc.domain}:${rpc.port}${rpc.path}`;
      let rpcData = {
        id: new Date().getTime(),
        jsonrpc: "2.0",
        method: "aria2.addUri",
        params: [
          `token:${rpc.token}`,
          [link],
          {
            dir: rpc.dir,
            out: filename,
            header: [`Referer: https://www.aliyundrive.com/`],
          },
        ],
      };
      try {
        let res = await base.post(url, rpcData, { Referer: "https://www.aliyundrive.com/" }, "");
        if (res.result) return "success";
        return "fail";
      } catch (e) {
        return "fail";
      }
    },

    getSelectedList() {
      try {
        let selectedList = [];
        let reactDom = document.querySelector(pan.dom.list);
        let reactObj = base.findReact(reactDom, 1);
        let props = reactObj.pendingProps;
        if (props) {
          let fileList = props.dataSource || [];
          let selectedKeys = props.selectedKeys.split(",");
          fileList.forEach((val) => {
            if (selectedKeys.includes(val.fileId)) {
              selectedList.push(val);
            }
          });
        }
        return selectedList;
      } catch (e) {
        return [];
      }
    },

    detectPage() {
      let path = location.pathname;
      if (/^\/(drive)/.test(path)) return "home";
      if (/^\/(s|share)\//.test(path)) return "share";
      return "";
    },

    isOnlyFolder() {
      for (let i = 0; i < selectList.length; i++) {
        if (selectList[i].type === "file") return false;
      }
      return true;
    },

    showMainDialog(title, html, footer) {
      Swal.fire({
        title,
        html,
        footer,
        allowOutsideClick: false,
        showCloseButton: true,
        showConfirmButton: false,
        position: "top",
        width,
        padding: "15px 20px 5px",
        customClass,
      });
    },

    async initPanLinker() {
      base.initDefaultConfig();
      base.addPanLinkerStyle();
      pt = this.detectPage();
      let res = await base.post(`https://api.youxiaohou.com/config/v2/ali?ver=${version}&a=${author}`, {}, {}, "text");
      pan = JSON.parse(base.d(res));
      Object.freeze && Object.freeze(pan);
      pan.num === base.getValue("setting_init_code") || pan.license === base.getValue("license") ? this.addButton() : this.addInitButton();
      base.createTip();
      base.registerMenuCommand();
    },
  };

  let tianyi = {
    convertLinkToAria(link, filename, ua) {
      filename = base.fixFilename(filename);
      return encodeURIComponent(`aria2c "${link}" --out "${filename}"`);
    },

    convertLinkToBC(link, filename, ua) {
      let bc = `AA/${encodeURIComponent(filename)}/?url=${encodeURIComponent(link)}ZZ`;
      return encodeURIComponent(`bc://http/${base.e(bc)}`);
    },

    convertLinkToCurl(link, filename, ua) {
      let terminal = base.getValue("setting_terminal_type");
      filename = base.fixFilename(filename);
      return encodeURIComponent(`${terminal !== "wp" ? "curl" : "curl.exe"} -L -C - "${link}" -o "${filename}"`);
    },

    addPageListener() {
      doc.on("click", ".pl-button-mode", (e) => {
        mode = e.target.dataset.mode;
        Swal.showLoading();
        this.getPCSLink();
      });
      doc.on("click", ".listener-link-api", async (e) => {
        e.preventDefault();
        $("#downloadIframe").attr("src", e.currentTarget.dataset.link);
      });
      doc.on("click", ".listener-link-aria, .listener-copy-all", (e) => {
        e.preventDefault();
        base.setClipboard(decodeURIComponent(e.target.dataset.link));
        $(e.target).text("复制成功，快去粘贴吧！").animate({ opacity: "0.5" }, "slow");
      });
      doc.on("click", ".listener-link-rpc", async (e) => {
        let target = $(e.currentTarget);
        target.find(".icon").remove();
        target.find(".pl-loading").remove();
        target.prepend(base.createLoading());
        let res = await this.sendLinkToRPC(e.currentTarget.dataset.filename, e.currentTarget.dataset.link);
        if (res === "success") {
          $(".listener-rpc-task").show();
          target.removeClass("pl-btn-danger").html("发送成功，快去看看吧！").animate({ opacity: "0.5" }, "slow");
        } else {
          target.addClass("pl-btn-danger").text("发送失败，请检查您的RPC配置信息！").animate({ opacity: "0.5" }, "slow");
        }
      });
      doc.on("click", ".listener-send-rpc", (e) => {
        $(".listener-link-rpc").click();
        $(e.target).text("发送完成，发送结果见上方按钮！").animate({ opacity: "0.5" }, "slow");
      });
      doc.on("click", ".listener-open-setting", () => {
        base.showSetting();
      });
      doc.on("click", ".listener-rpc-task", () => {
        let rpc = JSON.stringify({
            domain: base.getValue("setting_rpc_domain"),
            port: base.getValue("setting_rpc_port"),
          }),
          url = `${pan.d}/?rpc=${base.e(rpc)}#${base.getValue("setting_rpc_token")}`;
        GM_openInTab(url, { active: true });
      });
    },

    addButton() {
      if (!pt) return;
      let $toolWrap;
      let $button = $(
        `<div class="tianyi-button pl-button">下载助手<ul class="pl-dropdown-menu" style="top: 26px;"><li class="pl-dropdown-menu-item pl-button-mode" data-mode="api">API下载</li><li class="pl-dropdown-menu-item pl-button-mode" data-mode="aria" >Aria下载</li><li class="pl-dropdown-menu-item pl-button-mode" data-mode="rpc">RPC下载</li><li class="pl-dropdown-menu-item pl-button-mode" data-mode="curl">cURL下载</li><li class="pl-dropdown-menu-item pl-button-mode" data-mode="bc" >BC下载</li><li class="pl-dropdown-menu-item pl-button-mode listener-open-setting">助手设置</li>${
          pan.code == 200 && version < pan.version ? pan.new : ""
        }</ul></div>`
      );
      if (pt === "home") {
        base.listenElement(pan.btn.home, () => {
          $toolWrap = $(pan.btn.home);
          $(".pl-button").length === 0 && $toolWrap.prepend($button);
        });
      }
      if (pt === "share") {
        base.listenElement(pan.btn.share, () => {
          $toolWrap = $(pan.btn.share);
          $(".pl-button").length === 0 && $toolWrap.prepend($button);
        });
      }
      base.createDownloadIframe();
      this.addPageListener();
    },

    addInitButton() {
      if (!pt) return;
      let $toolWrap;
      let $button = $(`<div class="tianyi-button pl-button-init">下载助手</div>`);
      if (pt === "home") {
        base.listenElement(pan.btn.home, () => {
          $toolWrap = $(pan.btn.home);
          $(".pl-button-init").length === 0 && $toolWrap.prepend($button);
        });
      }
      if (pt === "share") {
        $button.css({ "margin-right": "10px" });
        base.listenElement(pan.btn.share, () => {
          $toolWrap = $(pan.btn.share);
          $(".pl-button-init").length === 0 && $toolWrap.prepend($button);
        });
      }
      $button.click(() => base.initDialog());
    },

    async getToken() {
      let res = await base.getFinalUrl(pan.pcs[1], {});
      let accessToken = res.match(/accessToken=(\w+)/)?.[1];
      accessToken && base.setStorage("accessToken", accessToken);
      return accessToken;
    },

    async getFileUrlByOnce(item, index, token) {
      try {
        if (item.downloadUrl)
          return {
            index,
            downloadUrl: item.downloadUrl,
          };
        let time = Date.now(),
          fileId = item.fileId,
          o = "AccessToken=" + token + "&Timestamp=" + time + "&fileId=" + fileId,
          url = pan.pcs[2] + "?fileId=" + fileId;
        if (item.shareId) {
          o = "AccessToken=" + token + "&Timestamp=" + time + "&dt=1&fileId=" + fileId + "&shareId=" + item.shareId;
          url += "&dt=1&shareId=" + item.shareId;
        }
        let sign = md5(o).toString();
        let res = await base.get(url, {
          accept: "application/json;charset=UTF-8",
          "sign-type": 1,
          accesstoken: token,
          timestamp: time,
          signature: sign,
        });
        if (res.res_code === 0) {
          return {
            index,
            downloadUrl: res.fileDownloadUrl,
          };
        } else if (res.errorCode === "InvalidSessionKey") {
          return {
            index,
            downloadUrl: "提示：请先登录网盘！",
          };
        } else if (res.res_code === "ShareNotFoundFlatDir") {
          return {
            index,
            downloadUrl: "提示：请先[转存]文件，👉前往[我的网盘]中下载！",
          };
        } else {
          return {
            index,
            downloadUrl: "获取下载地址失败，请刷新重试！",
          };
        }
      } catch (e) {
        return {
          index,
          downloadUrl: "获取下载地址失败，请刷新重试！",
        };
      }
    },

    async getPCSLink() {
      selectList = this.getSelectedList();
      if (selectList.length === 0) {
        return message.error("提示：请先勾选要下载的文件！");
      }
      if (this.isOnlyFolder()) {
        return message.error("提示：请打开文件夹后勾选文件！");
      }
      let token = base.getStorage("accessToken") || (await this.getToken());
      if (!token) {
        return message.error("提示：请先登录网盘！");
      }
      let queue = [];
      selectList.forEach((item, index) => {
        queue.push(this.getFileUrlByOnce(item, index, token));
      });

      const res = await Promise.all(queue);
      res.forEach((val) => {
        selectList[val.index].downloadUrl = val.downloadUrl;
      });

      let html = this.generateDom(selectList);
      this.showMainDialog(pan[mode][0], html, pan[mode][1]);
    },

    generateDom(list) {
      let content = '<div class="pl-main">';
      let alinkAllText = "";
      list.forEach((v, i) => {
        if (v.isFolder) return;
        let filename = v.fileName;
        let size = base.sizeFormat(v.size);
        let dlink = v.downloadUrl;
        if (mode === "api") {
          $X.runcmd(`IDMan /n /d "${dlink}" /f "${filename}" /p "D:\\Download\\Pan"`);
          console.log(dlink);
          content += `<div class="pl-item">
                              <div class="pl-item-name listener-tip" data-size="${size}">${filename}</div>
                              <a class="pl-item-link listener-link-api" data-filename="${filename}" data-link="${dlink}" data-index="${i}">${dlink}</a>
                              </div>`;
        }
        if (mode === "aria") {
          let alink = this.convertLinkToAria(dlink, filename, navigator.userAgent);
          alinkAllText += alink + "\r\n";
          content += `<div class="pl-item">
                              <div class="pl-item-name listener-tip" data-size="${size}">${filename}</div>
                              <a class="pl-item-link listener-link-aria" href="${alink}" title="点击复制aria2c链接" data-filename="${filename}" data-link="${alink}">${decodeURIComponent(alink)}</a> </div>`;
        }
        if (mode === "rpc") {
          content += `<div class="pl-item">
                              <div class="pl-item-name listener-tip" data-size="${size}">${filename}</div>
                              <button class="pl-item-link listener-link-rpc pl-btn-primary pl-btn-info" data-filename="${filename}" data-link="${dlink}"><em class="icon icon-device"></em><span style="margin-left: 5px;">推送到 RPC 下载器</span></button></div>`;
        }
        if (mode === "curl") {
          let alink = this.convertLinkToCurl(dlink, filename, navigator.userAgent);
          alinkAllText += alink + "\r\n";
          content += `<div class="pl-item">
                              <div class="pl-item-name listener-tip" data-size="${size}">${filename}</div>
                              <a class="pl-item-link listener-link-aria" href="${alink}" title="点击复制curl链接" data-filename="${filename}" data-link="${alink}">${decodeURIComponent(alink)}</a> </div>`;
        }
        if (mode === "bc") {
          let alink = this.convertLinkToBC(dlink, filename, navigator.userAgent);
          content += `<div class="pl-item">
                              <div class="pl-item-name listener-tip" data-size="${size}">${filename}</div>
                              <a class="pl-item-link" href="${decodeURIComponent(alink)}" title="点击用比特彗星下载" data-filename="${filename}" data-link="${alink}">${decodeURIComponent(alink)}</a> </div>`;
        }
      });
      content += "</div>";
      if (mode === "aria") content += `<div class="pl-extra"><button class="pl-btn-primary listener-copy-all" data-link="${alinkAllText}">复制全部链接</button></div>`;
      if (mode === "rpc") {
        let rpc = base.getValue("setting_rpc_domain") + ":" + base.getValue("setting_rpc_port") + base.getValue("setting_rpc_path");
        content += `<div class="pl-extra"><button class="pl-btn-primary listener-send-rpc">发送全部链接</button><button title="${rpc}" class="pl-btn-primary pl-btn-warning listener-open-setting" style="margin-left: 10px">设置 RPC 参数（当前为：${rpc}）</button><button class="pl-btn-primary pl-btn-success listener-rpc-task" style="margin-left: 10px;display: none">查看下载任务</button></div>`;
      }
      if (mode === "curl")
        content += `<div class="pl-extra"><button class="pl-btn-primary listener-copy-all" data-link="${alinkAllText}">复制全部链接</button><button class="pl-btn-primary pl-btn-warning listener-open-setting" style="margin-left: 10px;">设置终端类型（当前为：${
          terminalType[base.getValue("setting_terminal_type")]
        }）</button></div>`;
      return content;
    },

    async sendLinkToRPC(filename, link) {
      let rpc = {
        domain: base.getValue("setting_rpc_domain"),
        port: base.getValue("setting_rpc_port"),
        path: base.getValue("setting_rpc_path"),
        token: base.getValue("setting_rpc_token"),
        dir: base.getValue("setting_rpc_dir"),
      };

      let url = `${rpc.domain}:${rpc.port}${rpc.path}`;
      let rpcData = {
        id: new Date().getTime(),
        jsonrpc: "2.0",
        method: "aria2.addUri",
        params: [
          `token:${rpc.token}`,
          [link],
          {
            dir: rpc.dir,
            out: filename,
            header: [],
          },
        ],
      };
      try {
        let res = await base.post(url, rpcData, {}, "");
        if (res.result) return "success";
        return "fail";
      } catch (e) {
        return "fail";
      }
    },

    getSelectedList() {
      try {
        return document.querySelector(".c-file-list").__vue__.selectedList;
      } catch (e) {
        return [document.querySelector(".info-detail").__vue__.fileDetail];
      }
    },

    detectPage() {
      let path = location.pathname;
      if (/^\/web\/main/.test(path)) return "home";
      if (/^\/web\/share/.test(path)) return "share";
      return "";
    },

    isOnlyFolder() {
      for (let i = 0; i < selectList.length; i++) {
        if (!selectList[i].isFolder) return false;
      }
      return true;
    },

    showMainDialog(title, html, footer) {
      Swal.fire({
        title,
        html,
        footer,
        allowOutsideClick: false,
        showCloseButton: true,
        showConfirmButton: false,
        position: "top",
        width,
        padding: "15px 20px 5px",
        customClass,
      });
    },

    async initPanLinker() {
      base.initDefaultConfig();
      base.addPanLinkerStyle();
      pt = this.detectPage();
      let res = await base.post(`https://api.youxiaohou.com/config/v2/tianyi?ver=${version}&a=${author}`, {}, {}, "text");
      pan = JSON.parse(base.d(res));
      Object.freeze && Object.freeze(pan);
      pan.num === base.getValue("setting_init_code") || pan.license === base.getValue("license") ? this.addButton() : this.addInitButton();
      this.getToken();
      base.createTip();
      base.registerMenuCommand();
    },
  };

  let xunlei = {
    convertLinkToAria(link, filename, ua) {
      filename = base.fixFilename(filename);
      return encodeURIComponent(`aria2c "${link}" --out "${filename}"`);
    },

    convertLinkToBC(link, filename, ua) {
      let bc = `AA/${encodeURIComponent(filename)}/?url=${encodeURIComponent(link)}ZZ`;
      return encodeURIComponent(`bc://http/${base.e(bc)}`);
    },

    convertLinkToCurl(link, filename, ua) {
      let terminal = base.getValue("setting_terminal_type");
      filename = base.fixFilename(filename);
      return encodeURIComponent(`${terminal !== "wp" ? "curl" : "curl.exe"} -L -C - "${link}" -o "${filename}"`);
    },

    addPageListener() {
      doc.on("click", ".pl-button-mode", (e) => {
        mode = e.target.dataset.mode;
        Swal.showLoading();
        this.getPCSLink();
      });
      doc.on("click", ".listener-link-api", async (e) => {
        e.preventDefault();
        $("#downloadIframe").attr("src", e.currentTarget.dataset.link);
      });
      doc.on("click", ".listener-link-api-btn", async (e) => {
        base.setClipboard(e.target.dataset.filename);
        $(e.target).text("复制成功").animate({ opacity: "0.5" }, "slow");
      });
      doc.on("click", ".listener-link-bc-btn", async (e) => {
        let mirror = base.getMirrorList(e.target.dataset.dlink, pan.mirror);
        base.setClipboard(mirror);
        $(e.target).text("复制成功").animate({ opacity: "0.5" }, "slow");
      });
      doc.on("click", ".listener-link-aria, .listener-copy-all", (e) => {
        e.preventDefault();
        base.setClipboard(decodeURIComponent(e.target.dataset.link));
        $(e.target).text("复制成功，快去粘贴吧！").animate({ opacity: "0.5" }, "slow");
      });
      doc.on("click", ".listener-link-rpc", async (e) => {
        let target = $(e.currentTarget);
        target.find(".icon").remove();
        target.find(".pl-loading").remove();
        target.prepend(base.createLoading());
        let res = await this.sendLinkToRPC(e.currentTarget.dataset.filename, e.currentTarget.dataset.link);
        if (res === "success") {
          $(".listener-rpc-task").show();
          target.removeClass("pl-btn-danger").html("发送成功，快去看看吧！").animate({ opacity: "0.5" }, "slow");
        } else {
          target.addClass("pl-btn-danger").text("发送失败，请检查您的RPC配置信息！").animate({ opacity: "0.5" }, "slow");
        }
      });
      doc.on("click", ".listener-send-rpc", (e) => {
        $(".listener-link-rpc").click();
        $(e.target).text("发送完成，发送结果见上方按钮！").animate({ opacity: "0.5" }, "slow");
      });
      doc.on("click", ".listener-open-setting", () => {
        base.showSetting();
      });
      doc.on("click", ".listener-rpc-task", () => {
        let rpc = JSON.stringify({
            domain: base.getValue("setting_rpc_domain"),
            port: base.getValue("setting_rpc_port"),
          }),
          url = `${pan.d}/?rpc=${base.e(rpc)}#${base.getValue("setting_rpc_token")}`;
        GM_openInTab(url, { active: true });
      });
    },

    addButton() {
      if (!pt) return;
      let $toolWrap;
      let $button = $(
        `<div class="xunlei-button pl-button"><i class="xlpfont xlp-download"></i><span style="font-size: 13px;margin-left: 6px;">下载助手</span><ul class="pl-dropdown-menu" style="top: 34px;"><li class="pl-dropdown-menu-item pl-button-mode" data-mode="api">API下载</li><li class="pl-dropdown-menu-item pl-button-mode" data-mode="aria" >Aria下载</li><li class="pl-dropdown-menu-item pl-button-mode" data-mode="rpc">RPC下载</li><li class="pl-dropdown-menu-item pl-button-mode" data-mode="curl">cURL下载</li><li class="pl-dropdown-menu-item pl-button-mode" data-mode="bc" >BC下载</li><li class="pl-dropdown-menu-item pl-button-mode listener-open-setting">助手设置</li>${
          pan.code == 200 && version < pan.version ? pan.new : ""
        }</ul></div>`
      );
      if (pt === "home") {
        base.listenElement(pan.btn.home, () => {
          $toolWrap = $(pan.btn.home);
          $(".pl-button").length === 0 && $toolWrap.prepend($button);
        });
      }
      if (pt === "share") {
        $button.css({ "margin-right": "10px" });
        base.listenElement(pan.btn.share, () => {
          $toolWrap = $(pan.btn.share);
          $(".pl-button").length === 0 && $toolWrap.prepend($button);
        });
      }
      base.createDownloadIframe();
      this.addPageListener();
    },

    addInitButton() {
      if (!pt) return;
      let $toolWrap;
      let $button = $(`<div class="xunlei-button pl-button-init"><i class="xlpfont xlp-download"></i><span style="font-size: 13px;margin-left: 6px;">下载助手</span></div>`);
      if (pt === "home") {
        base.listenElement(pan.btn.home, () => {
          $toolWrap = $(pan.btn.home);
          $(".pl-button-init").length === 0 && $toolWrap.prepend($button);
        });
      }
      if (pt === "share") {
        $button.css({ "margin-right": "10px" });
        base.listenElement(pan.btn.share, () => {
          $toolWrap = $(pan.btn.share);
          $(".pl-button-init").length === 0 && $toolWrap.prepend($button);
        });
      }
      $button.click(() => base.initDialog());
    },

    getToken() {
      let credentials = {},
        captcha = {};
      for (let i = 0; i < localStorage.length; i++) {
        if (/^credentials_/.test(localStorage.key(i))) {
          credentials = base.getStorage(localStorage.key(i));
          base.setStorage("");
        }
        if (/^captcha_[\w]{16}/.test(localStorage.key(i))) {
          captcha = base.getStorage(localStorage.key(i));
        }
      }
      let deviceid = /(\w{32})/.exec(base.getStorage("deviceid").split(","))[0];
      let token = {
        credentials,
        captcha,
        deviceid,
      };
      return token;
    },

    async getFileUrlByOnce(item, index, token) {
      try {
        if (item.downloadUrl)
          return {
            index,
            downloadUrl: item.downloadUrl,
          };
        let res = await base.get(pan.pcs[0] + item.id, {
          Authorization: `${token.credentials.token_type} ${token.credentials.access_token}`,
          "content-type": "application/json",
          "x-captcha-token": token.captcha.token,
          "x-device-id": token.deviceid,
        });
        if (res.web_content_link) {
          return {
            index,
            downloadUrl: res.web_content_link,
          };
        } else {
          return {
            index,
            downloadUrl: "获取下载地址失败，请刷新重试！",
          };
        }
      } catch (e) {
        return message.error("提示：请先登录网盘后刷新页面！");
      }
    },

    async getPCSLink() {
      selectList = this.getSelectedList();
      if (selectList.length === 0) {
        return message.error("提示：请先勾选要下载的文件！");
      }
      if (this.isOnlyFolder()) {
        return message.error("提示：请打开文件夹后勾选文件！");
      }
      if (pt === "home") {
        let queue = [];
        let token = this.getToken();
        selectList.forEach((item, index) => {
          queue.push(this.getFileUrlByOnce(item, index, token));
        });
        const res = await Promise.all(queue);
        res.forEach((val) => {
          selectList[val.index].downloadUrl = val.downloadUrl;
        });
      } else {
        let dialog = await Swal.fire({
          toast: true,
          icon: "info",
          title: `提示：请将文件<span class="tag-danger">[保存到网盘]</span>👉前往<span class="tag-danger">[我的网盘]</span>中下载！`,
          showConfirmButton: true,
          confirmButtonText: "点击保存",
          position: "top",
        });
        if (dialog.isConfirmed) {
          document.querySelector(".saveToCloud").click();
          return;
        }
      }
      let html = this.generateDom(selectList);
      this.showMainDialog(pan[mode][0], html, pan[mode][1]);
    },

    generateDom(list) {
      let content = '<div class="pl-main">';
      let alinkAllText = "";
      list.forEach((v, i) => {
        if (v.kind === "drive#folder") return;
        let filename = v.name;
        let size = base.sizeFormat(+v.size);
        let dlink = v.downloadUrl;
        if (mode === "api") {
          $X.runcmd(`IDMan /n /d "${dlink}" /f "${filename}" /p "D:\\Download\\Pan"`);
          console.log(dlink);
          content += `<div class="pl-item">
                              <div class="pl-item-name listener-tip" data-size="${size}">${filename}</div>
                              <a class="pl-item-link listener-link-api" data-filename="${filename}" data-link="${dlink}" data-index="${i}">${dlink}</a>
                              <div class="pl-item-btn listener-link-api-btn" data-filename="${filename}">复制文件名</div>
                              </div>`;
        }
        if (mode === "aria") {
          let alink = this.convertLinkToAria(dlink, filename, navigator.userAgent);
          alinkAllText += alink + "\r\n";
          content += `<div class="pl-item">
                              <div class="pl-item-name listener-tip" data-size="${size}">${filename}</div>
                              <a class="pl-item-link listener-link-aria" href="${alink}" title="点击复制aria2c链接" data-filename="${filename}" data-link="${alink}">${decodeURIComponent(alink)}</a> </div>`;
        }
        if (mode === "rpc") {
          content += `<div class="pl-item">
                              <div class="pl-item-name listener-tip" data-size="${size}">${filename}</div>
                              <button class="pl-item-link listener-link-rpc pl-btn-primary pl-btn-info" data-filename="${filename}" data-link="${dlink}"><em class="icon icon-device"></em><span style="margin-left: 5px;">推送到 RPC 下载器</span></button></div>`;
        }
        if (mode === "curl") {
          let alink = this.convertLinkToCurl(dlink, filename, navigator.userAgent);
          alinkAllText += alink + "\r\n";
          content += `<div class="pl-item">
                              <div class="pl-item-name listener-tip" data-size="${size}">${filename}</div>
                              <a class="pl-item-link listener-link-aria" href="${alink}" title="点击复制curl链接" data-filename="${filename}" data-link="${alink}">${decodeURIComponent(alink)}</a> </div>`;
        }
        if (mode === "bc") {
          let alink = this.convertLinkToBC(dlink, filename, navigator.userAgent);
          content += `<div class="pl-item">
                              <div class="pl-item-name listener-tip" data-size="${size}">${filename}</div>
                              <a class="pl-item-link" href="${decodeURIComponent(alink)}" title="点击用比特彗星下载" data-filename="${filename}" data-link="${alink}">${decodeURIComponent(alink)}</a> 
                              <div class="pl-item-btn listener-link-bc-btn" data-dlink="${dlink}">复制镜像地址</div>
                              </div>`;
        }
      });
      content += "</div>";
      if (mode === "aria") content += `<div class="pl-extra"><button class="pl-btn-primary listener-copy-all" data-link="${alinkAllText}">复制全部链接</button></div>`;
      if (mode === "rpc") {
        let rpc = base.getValue("setting_rpc_domain") + ":" + base.getValue("setting_rpc_port") + base.getValue("setting_rpc_path");
        content += `<div class="pl-extra"><button class="pl-btn-primary listener-send-rpc">发送全部链接</button><button title="${rpc}" class="pl-btn-primary pl-btn-warning listener-open-setting" style="margin-left: 10px">设置 RPC 参数（当前为：${rpc}）</button><button class="pl-btn-primary pl-btn-success listener-rpc-task" style="margin-left: 10px;display: none">查看下载任务</button></div>`;
      }
      if (mode === "curl")
        content += `<div class="pl-extra"><button class="pl-btn-primary listener-copy-all" data-link="${alinkAllText}">复制全部链接</button><button class="pl-btn-primary pl-btn-warning listener-open-setting" style="margin-left: 10px;">设置终端类型（当前为：${
          terminalType[base.getValue("setting_terminal_type")]
        }）</button></div>`;
      return content;
    },

    async sendLinkToRPC(filename, link) {
      let rpc = {
        domain: base.getValue("setting_rpc_domain"),
        port: base.getValue("setting_rpc_port"),
        path: base.getValue("setting_rpc_path"),
        token: base.getValue("setting_rpc_token"),
        dir: base.getValue("setting_rpc_dir"),
      };

      let url = `${rpc.domain}:${rpc.port}${rpc.path}`;
      let rpcData = {
        id: new Date().getTime(),
        jsonrpc: "2.0",
        method: "aria2.addUri",
        params: [
          `token:${rpc.token}`,
          [link],
          {
            dir: rpc.dir,
            out: filename,
            header: [],
          },
        ],
      };
      try {
        let res = await base.post(url, rpcData, {}, "");
        if (res.result) return "success";
        return "fail";
      } catch (e) {
        return "fail";
      }
    },

    getSelectedList() {
      try {
        let doms = document.querySelectorAll(".SourceListItem__item--XxpOC");
        let selectedList = [];
        for (let dom of doms) {
          let domVue = dom.__vue__;
          if (domVue.selected.includes(domVue.info.id)) {
            selectedList.push(domVue.info);
          }
        }
        return selectedList;
      } catch (e) {
        return [];
      }
    },

    detectPage() {
      let path = location.pathname;
      if (/^\/$/.test(path)) return "home";
      if (/^\/(s|share)\//.test(path)) return "share";
      return "";
    },

    isOnlyFolder() {
      for (let i = 0; i < selectList.length; i++) {
        if (selectList[i].kind === "drive#file") return false;
      }
      return true;
    },

    showMainDialog(title, html, footer) {
      Swal.fire({
        title,
        html,
        footer,
        allowOutsideClick: false,
        showCloseButton: true,
        showConfirmButton: false,
        position: "top",
        width,
        padding: "15px 20px 5px",
        customClass,
      });
    },

    async initPanLinker() {
      base.initDefaultConfig();
      base.addPanLinkerStyle();
      pt = this.detectPage();
      let res = await base.post(`https://api.youxiaohou.com/config/v2/xunlei?ver=${version}&a=${author}`, {}, {}, "text");
      pan = JSON.parse(base.d(res));
      Object.freeze && Object.freeze(pan);
      pan.num === base.getValue("setting_init_code") || pan.license === base.getValue("license") ? this.addButton() : this.addInitButton();
      base.createTip();
      base.registerMenuCommand();
    },
  };

  let quark = {
    convertLinkToAria(link, filename, ua) {
      filename = base.fixFilename(filename);
      return encodeURIComponent(`aria2c "${link}" --out "${filename}" --header "Cookie: ${document.cookie}"`);
    },

    convertLinkToBC(link, filename, ua) {
      let bc = `AA/${encodeURIComponent(filename)}/?url=${encodeURIComponent(link)}&cookie=${encodeURIComponent(document.cookie)}ZZ`;
      return encodeURIComponent(`bc://http/${base.e(bc)}`);
    },

    convertLinkToCurl(link, filename, ua) {
      let terminal = base.getValue("setting_terminal_type");
      filename = base.fixFilename(filename);
      return encodeURIComponent(`${terminal !== "wp" ? "curl" : "curl.exe"} -L -C - "${link}" -o "${filename}" -b "${document.cookie}"`);
    },

    addPageListener() {
      window.addEventListener("hashchange", async (e) => {
        let home = "https://pan.quark.cn/list#/",
          all = "https://pan.quark.cn/list#/list/all";
        if (e.oldURL === home && e.newURL === all) return;
        await base.sleep(150);
        if ($(".quark-button").length > 0) return;
        pan.num === base.getValue("setting_init_code") || pan.license === base.getValue("license") ? this.addButton() : this.addInitButton();
      });
      doc.on("click", ".pl-button-mode", (e) => {
        mode = e.target.dataset.mode;
        Swal.showLoading();
        this.getPCSLink();
      });
      doc.on("click", ".listener-link-api", async (e) => {
        e.preventDefault();
        $("#downloadIframe").attr("src", e.currentTarget.dataset.link);
      });
      doc.on("click", ".listener-link-aria, .listener-copy-all", (e) => {
        e.preventDefault();
        base.setClipboard(decodeURIComponent(e.target.dataset.link));
        $(e.target).text("复制成功，快去粘贴吧！").animate({ opacity: "0.5" }, "slow");
      });
      doc.on("click", ".listener-link-rpc", async (e) => {
        let target = $(e.currentTarget);
        target.find(".icon").remove();
        target.find(".pl-loading").remove();
        target.prepend(base.createLoading());
        let res = await this.sendLinkToRPC(e.currentTarget.dataset.filename, e.currentTarget.dataset.link);
        if (res === "success") {
          $(".listener-rpc-task").show();
          target.removeClass("pl-btn-danger").html("发送成功，快去看看吧！").animate({ opacity: "0.5" }, "slow");
        } else {
          target.addClass("pl-btn-danger").text("发送失败，请检查您的RPC配置信息！").animate({ opacity: "0.5" }, "slow");
        }
      });
      doc.on("click", ".listener-send-rpc", (e) => {
        $(".listener-link-rpc").click();
        $(e.target).text("发送完成，发送结果见上方按钮！").animate({ opacity: "0.5" }, "slow");
      });
      doc.on("click", ".listener-open-setting", () => {
        base.showSetting();
      });
      doc.on("click", ".listener-rpc-task", () => {
        let rpc = JSON.stringify({
            domain: base.getValue("setting_rpc_domain"),
            port: base.getValue("setting_rpc_port"),
          }),
          url = `${pan.d}/?rpc=${base.e(rpc)}#${base.getValue("setting_rpc_token")}`;
        GM_openInTab(url, { active: true });
      });
    },

    addButton() {
      if (!pt) return;
      let $toolWrap;
      let $button = $(
        `<div class="quark-button pl-button"><svg width="22" height="22" xmlns="http://www.w3.org/2000/svg"><g fill="none" fill-rule="evenodd" stroke="#555" stroke-width="2"><path stroke-linecap="round" stroke-linejoin="round" d="M9 12l2 2 2-2z"/><path d="M14 8h1.553c.85 0 1.16.093 1.47.267.311.174.556.43.722.756.166.326.255.65.255 1.54v4.873c0 .892-.089 1.215-.255 1.54-.166.327-.41.583-.722.757-.31.174-.62.267-1.47.267H6.447c-.85 0-1.16-.093-1.47-.267a1.778 1.778 0 01-.722-.756c-.166-.326-.255-.65-.255-1.54v-4.873c0-.892.089-1.215.255-1.54.166-.327.41-.583.722-.757.31-.174.62-.267 1.47-.267H11"/><path stroke-linecap="round" stroke-linejoin="round" d="M11 3v10"/></g></svg><b>下载助手</b><ul class="pl-dropdown-menu"><li class="pl-dropdown-menu-item pl-button-mode" data-mode="api">API下载</li><li class="pl-dropdown-menu-item pl-button-mode" data-mode="aria" >Aria下载</li><li class="pl-dropdown-menu-item pl-button-mode" data-mode="rpc">RPC下载</li><li class="pl-dropdown-menu-item pl-button-mode" data-mode="curl">cURL下载</li><li class="pl-dropdown-menu-item pl-button-mode" data-mode="bc" >BC下载</li><li class="pl-dropdown-menu-item pl-button-mode listener-open-setting">助手设置</li>${
          pan.code == 200 && version < pan.version ? pan.new : ""
        }</ul></div>`
      );
      if (pt === "home") {
        base.listenElement(pan.btn.home, () => {
          $toolWrap = $(pan.btn.home);
          $(".pl-button").length === 0 && $toolWrap.prepend($button);
        });
      }
      if (pt === "share") {
        $button.css({ "margin-right": "10px" });
        base.listenElement(pan.btn.share, () => {
          $toolWrap = $(pan.btn.share);
          $(".pl-button").length === 0 && $toolWrap.prepend($button);
        });
      }
    },

    addInitButton() {
      if (!pt) return;
      let $toolWrap;
      let $button = $(
        `<div class="quark-button pl-button-init"><svg width="22" height="22" xmlns="http://www.w3.org/2000/svg"><g fill="none" fill-rule="evenodd" stroke="#555" stroke-width="2"><path stroke-linecap="round" stroke-linejoin="round" d="M9 12l2 2 2-2z"/><path d="M14 8h1.553c.85 0 1.16.093 1.47.267.311.174.556.43.722.756.166.326.255.65.255 1.54v4.873c0 .892-.089 1.215-.255 1.54-.166.327-.41.583-.722.757-.31.174-.62.267-1.47.267H6.447c-.85 0-1.16-.093-1.47-.267a1.778 1.778 0 01-.722-.756c-.166-.326-.255-.65-.255-1.54v-4.873c0-.892.089-1.215.255-1.54.166-.327.41-.583.722-.757.31-.174.62-.267 1.47-.267H11"/><path stroke-linecap="round" stroke-linejoin="round" d="M11 3v10"/></g></svg><b>下载助手</b></div>`
      );
      if (pt === "home") {
        base.listenElement(pan.btn.home, () => {
          $toolWrap = $(pan.btn.home);
          $(".pl-button-init").length === 0 && $toolWrap.prepend($button);
        });
      }
      if (pt === "share") {
        $button.css({ "margin-right": "10px" });
        base.listenElement(pan.btn.share, () => {
          $toolWrap = $(pan.btn.share);
          $(".pl-button-init").length === 0 && $toolWrap.prepend($button);
        });
      }
      $button.click(() => base.initDialog());
    },

    async getPCSLink() {
      selectList = this.getSelectedList();
      if (selectList.length === 0) {
        return message.error("提示：请先勾选要下载的文件！");
      }
      if (this.isOnlyFolder()) {
        return message.error("提示：请打开文件夹后勾选文件！");
      }
      let fids = [];
      selectList.forEach((val) => {
        fids.push(val.fid);
      });
      if (pt === "home") {
        let res = await base.post(
          pan.pcs[0],
          {
            fids: fids,
          },
          { "content-type": "application/json;charset=utf-8", "user-agent": pan.ua }
        );
        if (res.code === 31001) {
          return message.error("提示：请先登录网盘！");
        }
        if (res.code !== 0) {
          return message.error("提示：获取链接失败！");
        }
        let html = this.generateDom(res.data);
        this.showMainDialog(pan[mode][0], html, pan[mode][1]);
      } else {
        let dialog = await Swal.fire({
          toast: true,
          icon: "info",
          title: `提示：请将文件<span class="tag-danger">[保存到网盘]</span>👉前往<span class="tag-danger">[我的网盘]</span>中下载！`,
          showConfirmButton: true,
          confirmButtonText: "点击保存",
          position: "top",
        });
        if (dialog.isConfirmed) {
          document.querySelector(".file-info_r").click();
          return;
        }
      }
    },

    generateDom(list) {
      let content = '<div class="pl-main">';
      let alinkAllText = "";
      list.forEach((v, i) => {
        if (v.file === false) return;
        let filename = v.file_name;
        let fid = v.fid;
        let size = base.sizeFormat(v.size);
        let dlink = v.download_url;
        if (mode === "api") {
          $X.runcmd(`IDMan /n /d "${dlink}" /f "${filename}" /p "D:\\Download\\Pan"`);
          console.log(dlink);
          content += `<div class="pl-item">
                              <div class="pl-item-name listener-tip" data-size="${size}">${filename}</div>
                              <a class="pl-item-link listener-link-api" data-fid="${fid}" data-filename="${filename}" data-link="${dlink}" data-index="${i}">${dlink}</a>
                              </div>`;
        }
        if (mode === "aria") {
          let alink = this.convertLinkToAria(dlink, filename, navigator.userAgent);
          alinkAllText += alink + "\r\n";
          content += `<div class="pl-item">
                              <div class="pl-item-name listener-tip" data-size="${size}">${filename}</div>
                              <a class="pl-item-link listener-link-aria" href="${alink}" title="点击复制aria2c链接" data-filename="${filename}" data-link="${alink}">${decodeURIComponent(alink)}</a> </div>`;
        }
        if (mode === "rpc") {
          content += `<div class="pl-item">
                              <div class="pl-item-name listener-tip" data-size="${size}">${filename}</div>
                              <button class="pl-item-link listener-link-rpc pl-btn-primary pl-btn-info" data-filename="${filename}" data-link="${dlink}"><em class="icon icon-device"></em><span style="margin-left: 5px;">推送到 RPC 下载器</span></button></div>`;
        }
        if (mode === "curl") {
          let alink = this.convertLinkToCurl(dlink, filename, navigator.userAgent);
          alinkAllText += alink + "\r\n";
          content += `<div class="pl-item">
                              <div class="pl-item-name listener-tip" data-size="${size}">${filename}</div>
                              <a class="pl-item-link listener-link-aria" href="${alink}" title="点击复制curl链接" data-filename="${filename}" data-link="${alink}">${decodeURIComponent(alink)}</a> </div>`;
        }
        if (mode === "bc") {
          let alink = this.convertLinkToBC(dlink, filename, navigator.userAgent);
          content += `<div class="pl-item">
                              <div class="pl-item-name listener-tip" data-size="${size}">${filename}</div>
                              <a class="pl-item-link" href="${decodeURIComponent(alink)}" title="点击用比特彗星下载" data-filename="${filename}" data-link="${alink}">${decodeURIComponent(alink)}</a> </div>`;
        }
      });
      content += "</div>";
      if (mode === "aria") content += `<div class="pl-extra"><button class="pl-btn-primary listener-copy-all" data-link="${alinkAllText}">复制全部链接</button></div>`;
      if (mode === "rpc") {
        let rpc = base.getValue("setting_rpc_domain") + ":" + base.getValue("setting_rpc_port") + base.getValue("setting_rpc_path");
        content += `<div class="pl-extra"><button class="pl-btn-primary listener-send-rpc">发送全部链接</button><button title="${rpc}" class="pl-btn-primary pl-btn-warning listener-open-setting" style="margin-left: 10px">设置 RPC 参数（当前为：${rpc}）</button><button class="pl-btn-primary pl-btn-success listener-rpc-task" style="margin-left: 10px;display: none">查看下载任务</button></div>`;
      }
      if (mode === "curl")
        content += `<div class="pl-extra"><button class="pl-btn-primary listener-copy-all" data-link="${alinkAllText}">复制全部链接</button><button class="pl-btn-primary pl-btn-warning listener-open-setting" style="margin-left: 10px;">设置终端类型（当前为：${
          terminalType[base.getValue("setting_terminal_type")]
        }）</button></div>`;
      return content;
    },

    async sendLinkToRPC(filename, link) {
      let rpc = {
        domain: base.getValue("setting_rpc_domain"),
        port: base.getValue("setting_rpc_port"),
        path: base.getValue("setting_rpc_path"),
        token: base.getValue("setting_rpc_token"),
        dir: base.getValue("setting_rpc_dir"),
      };

      let url = `${rpc.domain}:${rpc.port}${rpc.path}`;
      let rpcData = {
        id: new Date().getTime(),
        jsonrpc: "2.0",
        method: "aria2.addUri",
        params: [
          `token:${rpc.token}`,
          [link],
          {
            dir: rpc.dir,
            out: filename,
            header: [`Cookie: ${document.cookie}`],
          },
        ],
      };
      try {
        let res = await base.post(url, rpcData, { Cookie: document.cookie }, "");
        if (res.result) return "success";
        return "fail";
      } catch (e) {
        return "fail";
      }
    },

    getSelectedList() {
      try {
        let selectedList = [];
        let reactDom = document.getElementsByClassName("file-list")[0];
        let reactObj = base.findReact(reactDom);
        let props = reactObj.props;
        if (props) {
          let fileList = props.list || [];
          let selectedKeys = props.selectedRowKeys || [];
          fileList.forEach((val) => {
            if (selectedKeys.includes(val.fid)) {
              selectedList.push(val);
            }
          });
        }
        return selectedList;
      } catch (e) {
        return [];
      }
    },

    detectPage() {
      let path = location.pathname;
      if (/^\/(list)/.test(path)) return "home";
      if (/^\/(s|share)\//.test(path)) return "share";
      return "";
    },

    isOnlyFolder() {
      for (let i = 0; i < selectList.length; i++) {
        if (selectList[i].file) return false;
      }
      return true;
    },

    showMainDialog(title, html, footer) {
      Swal.fire({
        title,
        html,
        footer,
        allowOutsideClick: false,
        showCloseButton: true,
        showConfirmButton: false,
        position: "top",
        width,
        padding: "15px 20px 5px",
        customClass,
      });
    },

    async initPanLinker() {
      base.initDefaultConfig();
      base.addPanLinkerStyle();
      pt = this.detectPage();
      let res = await base.post(`https://api.youxiaohou.com/config/v2/quark?ver=${version}&a=${author}`, {}, {}, "text");
      pan = JSON.parse(base.d(res));
      Object.freeze && Object.freeze(pan);
      pan.num === base.getValue("setting_init_code") || pan.license === base.getValue("license") ? this.addButton() : this.addInitButton();
      this.addPageListener();
      base.createTip();
      base.createDownloadIframe();
      base.registerMenuCommand();
    },
  };

  let yidong = {
    convertLinkToAria(link, filename, ua) {
      filename = base.fixFilename(filename);
      return encodeURIComponent(`aria2c "${link}" --out "${filename}"`);
    },

    convertLinkToBC(link, filename, ua) {
      let bc = `AA/${encodeURIComponent(filename)}/?url=${encodeURIComponent(link)}ZZ`;
      return encodeURIComponent(`bc://http/${base.e(bc)}`);
    },

    convertLinkToCurl(link, filename, ua) {
      let terminal = base.getValue("setting_terminal_type");
      filename = base.fixFilename(filename);
      return encodeURIComponent(`${terminal !== "wp" ? "curl" : "curl.exe"} -L -C - "${link}" -o "${filename}"`);
    },

    addPageListener() {
      doc.on("click", ".pl-button-mode", (e) => {
        mode = e.target.dataset.mode;
        Swal.showLoading();
        this.getPCSLink();
      });
      doc.on("click", ".listener-link-api", async (e) => {
        e.preventDefault();
        $("#downloadIframe").attr("src", e.currentTarget.dataset.link);
      });
      doc.on("click", ".listener-link-aria, .listener-copy-all", (e) => {
        e.preventDefault();
        base.setClipboard(decodeURIComponent(e.target.dataset.link));
        $(e.target).text("复制成功，快去粘贴吧！").animate({ opacity: "0.5" }, "slow");
      });
      doc.on("click", ".listener-link-rpc", async (e) => {
        let target = $(e.currentTarget);
        target.find(".icon").remove();
        target.find(".pl-loading").remove();
        target.prepend(base.createLoading());
        let res = await this.sendLinkToRPC(e.currentTarget.dataset.filename, e.currentTarget.dataset.link);
        if (res === "success") {
          $(".listener-rpc-task").show();
          target.removeClass("pl-btn-danger").html("发送成功，快去看看吧！").animate({ opacity: "0.5" }, "slow");
        } else {
          target.addClass("pl-btn-danger").text("发送失败，请检查您的RPC配置信息！").animate({ opacity: "0.5" }, "slow");
        }
      });
      doc.on("click", ".listener-send-rpc", (e) => {
        $(".listener-link-rpc").click();
        $(e.target).text("发送完成，发送结果见上方按钮！").animate({ opacity: "0.5" }, "slow");
      });
      doc.on("click", ".listener-open-setting", () => {
        base.showSetting();
      });
      doc.on("click", ".listener-rpc-task", () => {
        let rpc = JSON.stringify({
            domain: base.getValue("setting_rpc_domain"),
            port: base.getValue("setting_rpc_port"),
          }),
          url = `${pan.d}/?rpc=${base.e(rpc)}#${base.getValue("setting_rpc_token")}`;
        GM_openInTab(url, { active: true });
      });
    },

    addButton() {
      if (!pt) return;
      let $toolWrap;
      let $button = $(
        `<div class="yidong-button pl-button">下载助手<ul class="pl-dropdown-menu" style="top: 36px;"><li class="pl-dropdown-menu-item pl-button-mode" data-mode="api">API下载</li><li class="pl-dropdown-menu-item pl-button-mode" data-mode="aria" >Aria下载</li><li class="pl-dropdown-menu-item pl-button-mode" data-mode="rpc">RPC下载</li><li class="pl-dropdown-menu-item pl-button-mode" data-mode="curl">cURL下载</li><li class="pl-dropdown-menu-item pl-button-mode" data-mode="bc" >BC下载</li><li class="pl-dropdown-menu-item pl-button-mode listener-open-setting">助手设置</li>${
          pan.code == 200 && version < pan.version ? pan.new : ""
        }</ul></div>`
      );
      if (pt === "home") {
        base.listenElement(pan.btn.home, () => {
          $toolWrap = $(pan.btn.home);
          $(".pl-button").length === 0 && $toolWrap.prepend($button);
        });
      }
      if (pt === "share") {
        $button.removeClass("yidong-button").addClass("yidong-share-button");
        base.listenElement(pan.btn.share, () => {
          $toolWrap = $(pan.btn.share);
          $(".pl-button").length === 0 && $toolWrap.prepend($button);
        });
      }
      base.createDownloadIframe();
      this.addPageListener();
    },

    addInitButton() {
      if (!pt) return;
      let $toolWrap;
      let $button = $(`<div class="yidong-button pl-button-init">下载助手</div>`);
      if (pt === "home") {
        base.listenElement(pan.btn.home, () => {
          $toolWrap = $(pan.btn.home);
          $(".pl-button-init").length === 0 && $toolWrap.prepend($button);
        });
      }
      if (pt === "share") {
        $button.removeClass("yidong-button").addClass("yidong-share-button");
        base.listenElement(pan.btn.share, () => {
          $toolWrap = $(pan.btn.share);
          $(".pl-button-init").length === 0 && $toolWrap.prepend($button);
        });
      }
      $button.click(() => base.initDialog());
    },

    getRandomString(len) {
      len = len || 16;
      let $chars = "ABCDEFGHJKMNPQRSTWXYZabcdefhijkmnprstwxyz2345678";
      let maxPos = $chars.length;
      let pwd = "";
      for (let i = 0; i < len; i++) {
        pwd += $chars.charAt(Math.floor(Math.random() * maxPos));
      }
      return pwd;
    },

    utob(str) {
      const u = String.fromCharCode;
      return str.replace(/[\uD800-\uDBFF][\uDC00-\uDFFFF]|[^\x00-\x7F]/g, (t) => {
        if (t.length < 2) {
          let e = t.charCodeAt(0);
          return e < 128 ? t : e < 2048 ? u(192 | (e >>> 6)) + u(128 | (63 & e)) : u(224 | ((e >>> 12) & 15)) + u(128 | ((e >>> 6) & 63)) + u(128 | (63 & e));
        }
        e = 65536 + 1024 * (t.charCodeAt(0) - 55296) + (t.charCodeAt(1) - 56320);
        return u(240 | ((e >>> 18) & 7)) + u(128 | ((e >>> 12) & 63)) + u(128 | ((e >>> 6) & 63)) + u(128 | (63 & e));
      });
    },

    getSign(e, t, a, n) {
      let r = "",
        i = "";
      if (t) {
        let s = Object.assign({}, t);
        (i = JSON.stringify(s)), (i = i.replace(/\s*/g, "")), (i = encodeURIComponent(i));
        let c = i.split(""),
          u = c.sort();
        i = u.join("");
      }
      let A = md5(base.e(this.utob(i)));
      let l = md5(a + ":" + n);
      return md5(A + l).toUpperCase();
    },

    async getFileUrlByOnce(item, index) {
      try {
        if (item.downloadUrl)
          return {
            index,
            downloadUrl: item.downloadUrl,
          };
        if (this.detectPage() === "home") {
          let body = {
            contentID: item.contentID,
            commonAccountInfo: { account: item.owner, accountType: 1 },
            operation: "0",
            inline: "0",
            extInfo: { isReturnCdnDownloadUrl: "1" },
          };
          let time = new Date(+new Date() + 8 * 3600 * 1000).toJSON().substr(0, 19).replace("T", " ");
          let key = this.getRandomString(16);
          let sign = this.getSign(undefined, body, time, key);

          let res = await base.post(pan.pcs[0], body, {
            authorization: base.getCookie("authorization"),
            "x-huawei-channelSrc": "10000034",
            "x-inner-ntwk": "2",
            "mcloud-channel": "1000101",
            "mcloud-client": "10701",
            "mcloud-sign": time + "," + key + "," + sign,
            "content-type": "application/json;charset=UTF-8",
            caller: "web",
            "CMS-DEVICE": "default",
            "x-DeviceInfo": "||9|7.12.0|chrome|118.0.0.0||windows 10||zh-CN|||",
            "x-SvcType": "1",
          });
          if (res.success) {
            return {
              index,
              downloadUrl: res.data.downloadURL,
            };
          } else {
            return {
              index,
              downloadUrl: "获取下载地址失败，请刷新重试！",
            };
          }
        }
        if (this.detectPage() === "share") {
          let vueDom = document.querySelector(".main_file_list").__vue__;

          let res = await base.post(pan.pcs[1], `linkId=${vueDom.linkID}&contentIds=${item.path}&catalogIds=`, {
            "Content-Type": "application/x-www-form-urlencoded",
          });
          if (res.code === 0) {
            return {
              index,
              downloadUrl: res.data.redrUrl,
            };
          } else {
            return {
              index,
              downloadUrl: "获取下载地址失败，请刷新重试！",
            };
          }
        }
      } catch (e) {
        return {
          index,
          downloadUrl: "获取下载地址失败，请刷新重试！",
        };
      }
    },

    async getPCSLink() {
      selectList = this.getSelectedList();
      if (selectList.length === 0) {
        return message.error("提示：请先勾选要下载的文件！");
      }
      if (this.isOnlyFolder()) {
        return message.error("提示：请打开文件夹后勾选文件！");
      }

      let queue = [];
      selectList.forEach((item, index) => {
        queue.push(this.getFileUrlByOnce(item, index));
      });

      const res = await Promise.all(queue);
      res.forEach((val) => {
        selectList[val.index].downloadUrl = val.downloadUrl;
      });

      let html = this.generateDom(selectList);
      this.showMainDialog(pan[mode][0], html, pan[mode][1]);
    },

    generateDom(list) {
      let content = '<div class="pl-main">';
      let alinkAllText = "";
      list.forEach((v, i) => {
        if (v.dirEtag || v.caName) return;
        let filename = v.contentName || v.coName;
        let size = base.sizeFormat(v.contentSize || v.coSize);
        let dlink = v.downloadUrl;
        if (mode === "api") {
          $X.runcmd(`IDMan /n /d "${dlink}" /f "${filename}" /p "D:\\Download\\Pan"`);
          console.log(dlink);
          content += `<div class="pl-item">
                              <div class="pl-item-name listener-tip" data-size="${size}">${filename}</div>
                              <a class="pl-item-link listener-link-api" data-filename="${filename}" data-link="${dlink}" data-index="${i}">${dlink}</a>
                              </div>`;
        }
        if (mode === "aria") {
          let alink = this.convertLinkToAria(dlink, filename, navigator.userAgent);
          alinkAllText += alink + "\r\n";
          content += `<div class="pl-item">
                              <div class="pl-item-name listener-tip" data-size="${size}">${filename}</div>
                              <a class="pl-item-link listener-link-aria" href="${alink}" title="点击复制aria2c链接" data-filename="${filename}" data-link="${alink}">${decodeURIComponent(alink)}</a> </div>`;
        }
        if (mode === "rpc") {
          content += `<div class="pl-item">
                              <div class="pl-item-name listener-tip" data-size="${size}">${filename}</div>
                              <button class="pl-item-link listener-link-rpc pl-btn-primary pl-btn-info" data-filename="${filename}" data-link="${dlink}"><em class="icon icon-device"></em><span style="margin-left: 5px;">推送到 RPC 下载器</span></button></div>`;
        }
        if (mode === "curl") {
          let alink = this.convertLinkToCurl(dlink, filename, navigator.userAgent);
          alinkAllText += alink + "\r\n";
          content += `<div class="pl-item">
                              <div class="pl-item-name listener-tip" data-size="${size}">${filename}</div>
                              <a class="pl-item-link listener-link-aria" href="${alink}" title="点击复制curl链接" data-filename="${filename}" data-link="${alink}">${decodeURIComponent(alink)}</a> </div>`;
        }
        if (mode === "bc") {
          let alink = this.convertLinkToBC(dlink, filename, navigator.userAgent);
          content += `<div class="pl-item">
                              <div class="pl-item-name listener-tip" data-size="${size}">${filename}</div>
                              <a class="pl-item-link" href="${decodeURIComponent(alink)}" title="点击用比特彗星下载" data-filename="${filename}" data-link="${alink}">${decodeURIComponent(alink)}</a> </div>`;
        }
      });
      content += "</div>";
      if (mode === "aria") content += `<div class="pl-extra"><button class="pl-btn-primary listener-copy-all" data-link="${alinkAllText}">复制全部链接</button></div>`;
      if (mode === "rpc") {
        let rpc = base.getValue("setting_rpc_domain") + ":" + base.getValue("setting_rpc_port") + base.getValue("setting_rpc_path");
        content += `<div class="pl-extra"><button class="pl-btn-primary listener-send-rpc">发送全部链接</button><button title="${rpc}" class="pl-btn-primary pl-btn-warning listener-open-setting" style="margin-left: 10px">设置 RPC 参数（当前为：${rpc}）</button><button class="pl-btn-primary pl-btn-success listener-rpc-task" style="margin-left: 10px;display: none">查看下载任务</button></div>`;
      }
      if (mode === "curl")
        content += `<div class="pl-extra"><button class="pl-btn-primary listener-copy-all" data-link="${alinkAllText}">复制全部链接</button><button class="pl-btn-primary pl-btn-warning listener-open-setting" style="margin-left: 10px;">设置终端类型（当前为：${
          terminalType[base.getValue("setting_terminal_type")]
        }）</button></div>`;
      return content;
    },

    async sendLinkToRPC(filename, link) {
      let rpc = {
        domain: base.getValue("setting_rpc_domain"),
        port: base.getValue("setting_rpc_port"),
        path: base.getValue("setting_rpc_path"),
        token: base.getValue("setting_rpc_token"),
        dir: base.getValue("setting_rpc_dir"),
      };

      let url = `${rpc.domain}:${rpc.port}${rpc.path}`;
      let rpcData = {
        id: new Date().getTime(),
        jsonrpc: "2.0",
        method: "aria2.addUri",
        params: [
          `token:${rpc.token}`,
          [link],
          {
            dir: rpc.dir,
            out: filename,
            header: [],
          },
        ],
      };
      try {
        let res = await base.post(url, rpcData, {}, "");
        if (res.result) return "success";
        return "fail";
      } catch (e) {
        return "fail";
      }
    },

    getSelectedList() {
      try {
        return document.querySelector(".main_file_list").__vue__.selectList.map((val) => val.item);
      } catch (e) {
        let vueDom = document.querySelector(".home-page").__vue__;
        let fileList = vueDom._computedWatchers.fileList.value;
        let dirList = vueDom._computedWatchers.dirList.value;
        let selectedFileIndex = vueDom.selectedFile;
        let selectedDirIndex = vueDom.selectedDir;
        let selectFileList = fileList.filter((v, i) => {
          return selectedFileIndex.includes(i);
        });
        let selectDirList = dirList.filter((v, i) => {
          return selectedDirIndex.includes(i);
        });
        return [...selectFileList, ...selectDirList];
      }
    },

    detectPage() {
      let path = location.pathname;
      if (/^\/w/.test(path)) return "home";
      if (/^\/link|shareweb/.test(path)) return "share";
      return "";
    },

    isOnlyFolder() {
      for (let i = 0; i < selectList.length; i++) {
        if (selectList[i].fileEtag || selectList[i].coName) return false;
      }
      return true;
    },

    showMainDialog(title, html, footer) {
      Swal.fire({
        title,
        html,
        footer,
        allowOutsideClick: false,
        showCloseButton: true,
        showConfirmButton: false,
        position: "top",
        width,
        padding: "15px 20px 5px",
        customClass,
      });
    },

    async initPanLinker() {
      base.initDefaultConfig();
      base.addPanLinkerStyle();
      pt = this.detectPage();
      let res = await base.post(`https://api.youxiaohou.com/config/v2/yidong?ver=${version}&a=${author}`, {}, {}, "text");
      pan = JSON.parse(base.d(res));
      Object.freeze && Object.freeze(pan);
      pan.num === base.getValue("setting_init_code") || pan.license === base.getValue("license") ? this.addButton() : this.addInitButton();
      base.createTip();
      base.registerMenuCommand();
    },
  };

  let main = {
    init() {
      if (/(pan|yun).baidu.com/.test(location.host)) {
        baidu.initPanLinker();
      }
      if (/openapi.baidu.com\/oauth/.test(location.href)) {
        baidu.initAuthorize();
      }
      if (/www.(aliyundrive|alipan).com/.test(location.host)) {
        ali.initPanLinker();
      }
      if (/cloud.189.cn/.test(location.host)) {
        tianyi.initPanLinker();
      }
      if (/pan.xunlei.com/.test(location.host)) {
        xunlei.initPanLinker();
      }
      if (/pan.quark.cn/.test(location.host)) {
        quark.initPanLinker();
      }
      if (/(yun|caiyun).139.com/.test(location.host)) {
        yidong.initPanLinker();
      }
    },
  };

  main.init();
})();
